Go to most recent revision |
Blame |
Last modification |
View Log
| RSS feed
/*
* Project: S.Ha.R.K.
*
* Coordinators:
* Giorgio Buttazzo <giorgio@sssup.it>
* Paolo Gai <pj@gandalf.sssup.it>
*
* Authors :
* Paolo Gai <pj@gandalf.sssup.it>
* Massimiliano Giorgi <massy@gandalf.sssup.it>
* Luca Abeni <luca@gandalf.sssup.it>
* (see the web pages for full authors list)
*
* ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
*
* http://www.sssup.it
* http://retis.sssup.it
* http://shark.sssup.it
*/
/**
------------
CVS : $Id: sermouse.c,v 1.1 2003-03-24 10:54:17 pj Exp $
File: $File$
Revision: $Revision: 1.1 $
Last update: $Date: 2003-03-24 10:54:17 $
------------
Author: Gerardo Lamastra
Date: 9/5/96
Revision: 1.1b
Date: 14/Apr/1999
Serial mouse driver
The mouse driver receives data from the serial RxServer()
Then it processes the mouse packet and sets the variables
representing the external mouse status.
**/
/*
* Copyright (C) 2000 Paolo Gai
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*
* Revision: 1.1
* Author: Massimiliano Giorgi
*
* This code were in mouse.c:
* -- there is a mouse server (Microsoft Mouse Protocol)
* -- there is "virtual operation" on a serial mouse
*/
/*
* Revison: 1.1b
* Changed to compile on 3.2.0
* -- added wcet time to all task
*/
/*
* -- changed internal structure to integrate "gpm" code
* -- now is used ONE task (not two!)
*/
//#include <string.h>
//#include <stdlib.h>
//#include <cons.h>
#include <kernel/kern.h>
#include <time.h>
//#include "sys/sys.h"
//#include "vm.h"
//#include "kern.h"
//#include "exc.h"
#include <drivers/scom.h>
#include <drivers/mouse.h>
#include "_mouse.h"
#include "sermouse.h"
#include <modules/sem.h>
//#define __DEBUG_MOUSE__
//#define __XTRA_DEBUG_MOUSE__
/* if defined: trace the initialization */
//#define __DEBUG_INIT__ 1
/* if defined: show data received from serial port on the screen */
//#define __DEBUG_DATAIN__ 1
/*
* The following code is derived from gpm (under GPL)
*/
#include "gpmcomp.h"
/*
* START!!
*
* mice.c - mouse definitions for gpm-Linux
*
* Copyright (C) 1993 Andrew Haylett <ajh@gec-mrc.co.uk>
* Copyright (C) 1994-1999 Alessandro Rubini <rubini@linux.it>
* Copyright (C) 1998,1999 Ian Zimmerman <itz@rahul.net>
*/
int M_ms(Gpm_Event *state, unsigned char *data)
{
/*
* some devices report a change of middle-button state by
* repeating the current button state (patch by Mark Lord)
*/
static unsigned char prev=0;
if (data[0] == 0x40 && !(prev|data[1]|data[2]))
state->buttons = GPM_B_MIDDLE; /* third button on MS compatible mouse */
else
state->buttons= ((data[0] & 0x20) >> 3) | ((data[0] & 0x10) >> 4);
prev = state->buttons;
state->dx= (signed char)(((data[0] & 0x03) << 6) | (data[1] & 0x3F));
state->dy= (signed char)(((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
return 0;
}
int M_ms_plus(Gpm_Event *state, unsigned char *data)
{
static unsigned char prev=0;
state->buttons= ((data[0] & 0x20) >> 3) | ((data[0] & 0x10) >> 4);
state->dx= (signed char)(((data[0] & 0x03) << 6) | (data[1] & 0x3F));
state->dy= (signed char)(((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
/* Allow motion *and* button change (Michael Plass) */
if ((state->dx==0) && (state->dy==0)
&& (state->buttons == (prev&~GPM_B_MIDDLE)))
state->buttons = prev^GPM_B_MIDDLE; /* no move or change: toggle middle */
else
state->buttons |= prev&GPM_B_MIDDLE; /* change: preserve middle */
prev=state->buttons;
return 0;
}
int M_ms_plus_lr(Gpm_Event *state, unsigned char *data)
{
/*
* Same as M_ms_plus but with an addition by Edmund GRIMLEY EVANS
*/
static unsigned char prev=0;
state->buttons= ((data[0] & 0x20) >> 3) | ((data[0] & 0x10) >> 4);
state->dx= (signed char)(((data[0] & 0x03) << 6) | (data[1] & 0x3F));
state->dy= (signed char)(((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
/* Allow motion *and* button change (Michael Plass) */
if ((state->dx==0) && (state->dy==0)
&& (state->buttons == (prev&~GPM_B_MIDDLE)))
state->buttons = prev^GPM_B_MIDDLE; /* no move or change: toggle middle */
else
state->buttons |= prev&GPM_B_MIDDLE; /* change: preserve middle */
/* Allow the user to reset state of middle button by pressing
the other two buttons at once (Edmund GRIMLEY EVANS) */
if (!((~state->buttons)&(GPM_B_LEFT|GPM_B_RIGHT)) &&
((~prev)&(GPM_B_LEFT|GPM_B_RIGHT)))
state->buttons &= ~GPM_B_MIDDLE;
prev=state->buttons;
return 0;
}
int M_bare(Gpm_Event *state, unsigned char *data)
{
/* a bare ms protocol */
state->buttons= ((data[0] & 0x20) >> 3) | ((data[0] & 0x10) >> 4);
state->dx= (signed char)(((data[0] & 0x03) << 6) | (data[1] & 0x3F));
state->dy= (signed char)(((data[0] & 0x0C) << 4) | (data[2] & 0x3F));
return 0;
}
int M_sun(Gpm_Event *state, unsigned char *data)
{
state->buttons= (~data[0]) & 0x07;
state->dx= (signed char)(data[1]);
state->dy= -(signed char)(data[2]);
return 0;
}
int M_mm(Gpm_Event *state, unsigned char *data)
{
state->buttons= data[0] & 0x07;
state->dx= (data[0] & 0x10) ? data[1] : - data[1];
state->dy= (data[0] & 0x08) ? - data[2] : data[2];
return 0;
}
int M_logi(Gpm_Event *state, unsigned char *data) /* equal to mm */
{
state->buttons= data[0] & 0x07;
state->dx= (data[0] & 0x10) ? data[1] : - data[1];
state->dy= (data[0] & 0x08) ? - data[2] : data[2];
return 0;
}
int M_msc(Gpm_Event *state, unsigned char *data)
{
state->buttons= (~data[0]) & 0x07;
state->dx= (signed char)(data[1]) + (signed char)(data[3]);
state->dy= -((signed char)(data[2]) + (signed char)(data[4]));
return 0;
}
/*
* mice.c - mouse definitions for gpm-Linux
*
* END!!
*
*/
static BYTE proto_mouse0,proto_mouse1,proto_mouse2,proto_mouse3;
static char data[4]; // serial can go here?
static PID rx_server_pid = NIL;
static short int mouse_port = 0;
extern void (*com_fast)(int);
#define SBUFFERSIZE 64
#define SBUFFERMASK 0x3f
static BYTE sbuffer[SBUFFERSIZE];
static unsigned stail,shead;
static int scount;
void sermouse_fast(int);
int sermouse_open(void *info)
{
SERMOUSE_INFO *sinfo=(SERMOUSE_INFO*)info;
// MODEL m = BASE_MODEL;
int status;
#ifdef __DEBUG_INIT__
cprintf("sermouse_open: START\n");
#endif
/*
* Open serial device
*/
switch (sinfo->type) {
case MSCMOUSE:
case SUNMOUSE:
case LOGIMOUSE:
status=com_open(sinfo->port,1200,NONE,8,1); /* perhaps needs 2 stop bits */
break;
case MMMOUSE:
status=com_open(sinfo->port,1200,ODD,8,1);
break;
case MSMOUSE:
case MSPMOUSE:
case MSPLRMOUSE:
case BAREMOUSE:
default:
status=com_open(sinfo->port,1200,NONE,7,1);
break;
}
if (status!=1) return -1;
#ifdef __DEBUG_INIT__
cprintf("sermouse_open: COM port opened\n");
#endif
/* for some old logitech mouse */
if (sinfo->type==LOGIMOUSE) {
static struct {
int sample; char code[1];
} sampletab[]={
{ 0,{'O'}},
{ 15,{'J'}},
{ 27,{'K'}},
{ 42,{'L'}},
{ 60,{'R'}},
{ 85,{'M'}},
{125,{'Q'}},
{1E9,{'N'}}
};
int opt_sample=40;
int i;
/* UNTESTED!!! */
/* probably don't work*/
/* this stuff is peculiar of logitech mice, also for the serial ones */
com_send(sinfo->port,'S');
/* configure the sample rate */
for (i=0;opt_sample<=sampletab[i].sample;i++);
com_send(sinfo->port,sampletab[i].code[0]);
#ifdef __DEBUG_INIT__
cprintf("sermouse_open: 'logi' initialization done\n");
#endif
}
proto_mouse0=proto_mouse[0];
proto_mouse1=proto_mouse[1];
proto_mouse2=proto_mouse[2];
proto_mouse3=proto_mouse[3];
scount=0;
stail=0;
shead=1;
/*
* Create Serial port task
*/
/* MG: to use one task */
//task_def_arg(m,sinfo->port);
//task_def_wcet(m,500);
//rx_server_pid = task_create("RxServer",rxServer,HARD,APERIODIC,100,&m);
rx_server_pid=sinfo->pid;
/* test if exist the task...*/
if (rx_server_pid==-1) {
com_close(sinfo->port);
return -1;
}
com_fast=sermouse_fast;
com_server(sinfo->port,RX_FULL,NIL);
#ifdef __DEBUG_INIT__
cprintf("sermouse_open: COM task created\n");
#endif
/* MG: not needed (the fast handler activate the task) */
task_activate(rx_server_pid);
#ifdef __DEBUG_INIT__
//cprintf("sermouse_open: COM task activated\n");
#endif
mouse_port = sinfo->port;
com_link[sinfo->port].msk = RX_FULL;
com_write(sinfo->port,IER,RX_FULL);
/* this is for safety! */
com_link[sinfo->port].rx_buf = data;
#ifdef __DEBUG_INIT__
cprintf("sermouse_open: COM port configurated\n");
#endif
/* Enable RTS & DTR to activate mouse! */
sermouse_enable();
#ifdef __DEBUG_INIT__
cprintf("sermouse_open: mouse activated\n");
#endif
return 0;
}
/*
* return the server's address
*/
TASK (*sermouse_getserveraddr(SERMOUSE_INFO *infoptr))(void)
{
return generalmouse_server;
}
/*
* test if a mouse is present
*
* "When DTR line is toggled, mouse should send one data byte"
* "containing letter 'M' (ascii 77)."
* Tomi Engdahl <then@delta.hut.fi>
*
* this for Microsoft Serial mouse
*/
SERMOUSE_INFO *sermouse_present(void)
{
static SERMOUSE_INFO info;
int port;
int ret;
int found;
struct timespec delay;
delay.tv_sec = 0;
delay.tv_nsec = 500000000;
found=0;
for (port=COM1;port<=COM4;port++) {
ret=com_open(port,1200,NONE,7,1);
if (ret==1) {
com_write(port,MCR,0x0e);
nanosleep(&delay,NULL); /* necessary? */
com_write(port,MCR,0x0f);
nanosleep(&delay,NULL); /* necessary? */
ret=sem_wait(&com_link[mouse_port].rx_sem);
if (ret==TRUE) {
if (*(com_link[mouse_port].rx_buf)=='M') found=1;
}
com_close(port);
if (found) {
info.type=BAREMOUSE;
info.port=port;
return &info;
}
}
}
return NULL;
}
/* MG: the "virtual operation" operate on a serial port */
void sermouse_close(void)
{
com_close(mouse_port);
}
void sermouse_disable(void)
{
com_write(mouse_port,MCR,0);
}
void sermouse_enable(void)
{
com_write(mouse_port,MCR,0x0F);
}
void sermouse_wait(void)
{
task_endcycle();
/* changed to use one task */
//sem_wait(&com_link[mouse_port].rx_sem);
}
#ifdef __DEBUG_DATAIN__
/* debug values for keyboadget() and auxget() */
#define YDEB 2
#define COLORDEB WHITE
static int auxx=2;
#endif
int sermouse_get(BYTE *data)
{
SYS_FLAGS f;
int i;
// BYTE *p=data;
// BYTE t;
f=kern_fsave();
if (((stail+1)&SBUFFERMASK)==shead) {
kern_frestore(f);
return 0;
}
for (i=0;i<packetlen_mouse;i++) {
stail=(stail+1)&SBUFFERMASK;
*data++=sbuffer[stail];
}
kern_frestore(f);
#ifdef __DEBUG_DATAIN__
/*
* if debug...
* show all data from the serial port on YDEB line of the screen
*/
{
int i;
for (i=-packetlen_mouse;i<0;i++) {
if (auxx+5>=80) {
printf_xy(auxx,YDEB,COLORDEB," ");
auxx=2;
}
if (auxx==2) printf_xy(0,YDEB,COLORDEB,"S ");
printf_xy(auxx,YDEB,COLORDEB,"%02x > ",(unsigned)*(data+i));
auxx+=3;
}
}
#endif
return packetlen_mouse;
//*data=com_read(mouse_port,RBR);
//com_write(mouse_port,IER,com_link[mouse_port].msk);
//return 1;
/* changed to use one task */
//return *(com_link[mouse_port].rx_buf);
}
void sermouse_fast(int port)
{
SYS_FLAGS f;
BYTE data;
f=kern_fsave();
data=com_read(mouse_port,RBR);
com_write(mouse_port,IER,com_link[mouse_port].msk);
if (scount==0&&((data&proto_mouse0)!=proto_mouse1)) {
kern_frestore(f);
return;
} else if (scount==1&&((data&proto_mouse2)!=proto_mouse3)) {
shead=(shead-scount+SBUFFERSIZE)&SBUFFERMASK;
scount=0;
kern_frestore(f);
return;
}
scount++;
if (stail!=shead) {
sbuffer[shead]=data;
shead=(shead+1)&SBUFFERMASK;
} else {
shead=(shead-(scount-1)+SBUFFERSIZE)&SBUFFERMASK;
scount=0;
}
if (scount==packetlen_mouse) {
scount=0;
kern_frestore(f);
task_activate(rx_server_pid);
return;
}
kern_frestore(f);
}