Here is a new ps2mouse.c with intellimouse support. Could someone
without an intellimouse let me know if it still works for you?
I just hacked in the stuff for the intellimouse (*borrowing* liberally
from the gpm code), its ugly, but it works.
Here she is:
/*
(c) Copyright 2000 convergence integrated media GmbH.
All rights reserved.
Written by Denis Oliver Kropp <[EMAIL PROTECTED]> and
Andreas Hundt <[EMAIL PROTECTED]>.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/kd.h>
#include <sys/vt.h>
#include <sys/time.h>
#include <termios.h>
#include <pthread.h>
#include <directfb.h>
#include <core/coredefs.h>
#include <core/coretypes.h>
#include <core/input.h>
#include <core/reactor.h>
#include <misc/conf.h>
/* Stolen from the linux kernel (pc_keyb.h) */
#define PS2_SET_RES 0xE8 /* Set resolution */
#define PS2_SET_SCALE11 0xE6 /* Set 1:1 scaling */
#define PS2_SET_SCALE21 0xE7 /* Set 2:1 scaling */
#define PS2_GET_SCALE 0xE9 /* Get scaling factor */
#define PS2_SET_STREAM 0xEA /* Set stream mode */
#define PS2_SET_SAMPLE 0xF3 /* Set sample rate */
#define PS2_ENABLE_DEV 0xF4 /* Enable aux device */
#define PS2_DISABLE_DEV 0xF5 /* Disable aux device */
#define PS2_RESET 0xFF /* Reset aux device */
#define PS2_ACK 0xFA /* Command byte ACK. */
/*** mouse commands ***/
#define PS2_SEND_ID 0xF2
#define PS2_ID_ERROR -1
#define PS2_ID_PS2 0
#define PS2_ID_IMPS2 3
static int fd = -1;
static int mouseId;
static int packetLength = 3; /* Length of PS2 packet - 3 for Standard, 4 for
Intellimouse */
static DFBInputEvent x_motion;
static DFBInputEvent y_motion;
static DFBInputEvent z_motion;
static inline void ps2mouse_motion_initialize() {
x_motion.type = y_motion.type = z_motion.type = DIET_AXISMOTION;
x_motion.flags = y_motion.flags = z_motion.flags = DIEF_AXISREL | DIEF_TIMESTAMP;
x_motion.axisrel = y_motion.axisrel = z_motion.axisrel = 0;
x_motion.axis = DIAI_X;
y_motion.axis = DIAI_Y;
z_motion.axis = DIAI_Z;
}
static inline void ps2mouse_motion_compress( int dx, int dy, int dz ) {
x_motion.axisrel += dx;
y_motion.axisrel += dy;
z_motion.axisrel += dz;
}
static inline void ps2mouse_motion_realize( InputDevice *ps2mouse ) {
if ( x_motion.axisrel ) {
gettimeofday( &x_motion.timestamp, NULL );
reactor_dispatch( ps2mouse->reactor, &x_motion );
x_motion.axisrel = 0;
}
if ( y_motion.axisrel ) {
gettimeofday( &y_motion.timestamp, NULL );
reactor_dispatch( ps2mouse->reactor, &y_motion );
y_motion.axisrel = 0;
}
if ( z_motion.axisrel ) {
gettimeofday( &z_motion.timestamp, NULL );
reactor_dispatch( ps2mouse->reactor, &z_motion );
z_motion.axisrel = 0;
}
}
static void* ps2mouseEventThread(void *device) {
InputDevice *ps2mouse = (InputDevice*)device;
unsigned char packet[4];
unsigned char pos = 0;
unsigned char last_buttons = 0;
int readlen;
unsigned char buf[256];
if ( ps2mouse->number != 0 )
return (NULL);
ps2mouse_motion_initialize();
while ( (readlen = read(fd, buf, 256)) > 0 ) {
int i;
pthread_testcancel();
for ( i = 0; i < readlen; i++ ) {
if ( pos == 0 && (buf[i] & 0xc0) ) {
continue;
}
packet[pos++] = buf[i];
if ( pos == packetLength ) {
int dx, dy, dz;
int buttons;
pos = 0;
if ( !(packet[0] & 0x08) ) {
/* We've lost sync! */
i--; /* does this make sense? oh well, it will resync
eventually (or will it!?)*/
continue;
}
buttons = packet[0] & 0x07;
dx = (packet[0] & 0x10) ? packet[1]-256 : packet[1];
dy = (packet[0] & 0x20) ? -(packet[2]-256) : -packet[2];
if (mouseId == PS2_ID_IMPS2){
dz = (packet[4] & 0x80) ? packet[4] | 0xf0 :
packet[4] & 0x0f; /* Just strip off the extra buttons if present and sign extend the
4 bit value */
}
else {
dz = 0;
}
ps2mouse_motion_compress( dx, dy, dz );
if ( !dfb_config->mouse_motion_compression )
ps2mouse_motion_realize( device );
if ( last_buttons != buttons ) {
DFBInputEvent evt;
unsigned char changed_buttons = last_buttons ^ buttons;
/* make sure the compressed motion event is dispatched
before any button change */
ps2mouse_motion_realize( device );
evt.flags = DIEF_BUTTON | DIEF_TIMESTAMP;
gettimeofday( &evt.timestamp, NULL );
if ( changed_buttons & 0x01 ) {
evt.type = (buttons & 0x01) ? DIET_BUTTONPRESS :
DIET_BUTTONRELEASE;
evt.button = DIBI_LEFT;
reactor_dispatch( ps2mouse->reactor, &evt );
}
if ( changed_buttons & 0x02 ) {
evt.type = (buttons & 0x02) ? DIET_BUTTONPRESS :
DIET_BUTTONRELEASE;
evt.button = DIBI_RIGHT;
reactor_dispatch( ps2mouse->reactor, &evt );
}
if ( changed_buttons & 0x04 ) {
evt.type = (buttons & 0x04) ? DIET_BUTTONPRESS :
DIET_BUTTONRELEASE;
evt.button = DIBI_MIDDLE;
reactor_dispatch( ps2mouse->reactor, &evt );
}
last_buttons = buttons;
}
}
}
/* make sure the compressed motion event is dispatched,
necessary if the last packet was a motion event */
ps2mouse_motion_realize( device );
}
if ( readlen <= 0 && errno != EINTR )
PERRORMSG ("psmouse thread died\n");
pthread_testcancel();
return (NULL);
}
/* exported symbols */
int driver_probe() {
fd = open( "/dev/psaux", O_RDONLY );
if ( fd < 0 ) {
fd = open( "/dev/input/mice", O_RDONLY );
if ( fd < 0 ) {
return (0);
}
}
close( fd );
return (1);
}
/*
These 2 functions were HEAVILY inpsired (*cough*)
from the gpm package (written by the great
Alessandro Rubini and others)
*/
static int ps2GetId(void) {
unsigned char c = PS2_SEND_ID;
write(fd, &c, 1);
read(fd, &c, 1);
if ( c != PS2_ACK ) {
return(-1);
}
read(fd, &c, 1);
return(c);
}
static int ps2Write( unsigned char *data, size_t len) {
int i;
int error = 0;
for ( i = 0; i < len; i++ ) {
unsigned char c;
write(fd, &data[i], 1);
read(fd, &c, 1);
if ( c != PS2_ACK ) {
error++;
}
}
usleep (30000);
tcflush (fd, TCIFLUSH);
return(error);
}
int driver_init(InputDevice *device) {
static unsigned char basic_init[] = { PS2_ENABLE_DEV, PS2_SET_SAMPLE, 100};
static unsigned char imps2_init[] = { PS2_SET_SAMPLE, 200, PS2_SET_SAMPLE, 100,
PS2_SET_SAMPLE, 80,};
static unsigned char ps2_init[] = { PS2_SET_SCALE11, PS2_ENABLE_DEV,
PS2_SET_SAMPLE, 100, PS2_SET_RES, 3,};
fd = open( "/dev/psaux", O_RDWR );
if ( fd < 0 ) {
fd = open( "/dev/input/mice", O_RDWR );
if ( fd < 0 ) {
PERRORMSG( "DirectFB/PS2Mouse: Error opening `/dev/psaux' or
`/dev/input/mice' !\n" );
return (DFB_INIT);
}
}
/* Probe for Intellimouse - this should eventually be rolled into the main PS2
driver */
/* Do a basic init in case the mouse is confused */
ps2Write(basic_init, sizeof (basic_init));
/* Now try again and make sure we have a PS/2 mouse */
if ( ps2Write(basic_init, sizeof (basic_init)) != 0 ) {
printf("imps2: PS/2 mouse failed second init");
return (DFB_INIT);
}
/* Try to switch to 3 button mode */
if ( ps2Write(imps2_init, sizeof (imps2_init)) != 0 ) {
printf("imps2: PS/2 mouse failed 3 button mode switch");
return (DFB_INIT);
}
mouseId = ps2GetId();
if ( mouseId == (-1) ) {
printf("imps2: PS/2 mouse failed to read id, assuming standard PS/2");
mouseId = PS2_ID_PS2;
}
/* And do the real initialisation */
if ( ps2Write(ps2_init, sizeof (ps2_init)) != 0 ) {
printf("imps2: PS/2 mouse failed setup, continuing...");
}
if ( mouseId == PS2_ID_IMPS2 ){
packetLength = 4;
}
device->info.driver_name = "PS/2 Mouse";
device->info.driver_vendor = "convergence integrated media GmbH";
device->info.driver_version.major = 0;
device->info.driver_version.minor = 9;
device->id = DIDID_MOUSE;
device->desc.type = DIDTF_MOUSE;
device->desc.caps = DICAPS_AXIS | DICAPS_BUTTONS;
device->desc.max_axis = DIAI_Z;
device->desc.max_button = DIBI_MIDDLE; /* TODO: probe!? */
device->EventThread = ps2mouseEventThread;
return (DFB_OK);
}
void driver_deinit(InputDevice *device) {
if ( device->number != 0 )
return;
close( fd );
}