Files
Arquivotheca.SunOS-4.1.4/sys/sundev/ms.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

1281 lines
30 KiB
C

#ifndef lint
static char sccsid[] = "@(#)ms.c 1.1 94/10/31 Copyr 1987 Sun Micro";
#endif
/*
* Copyright (c) 1987 by Sun Microsystems, Inc.
*/
/*
* Mouse streams module.
*/
#include "ms.h"
#include <sys/param.h>
#include <sys/conf.h>
#include <sys/user.h>
#include <sys/proc.h>
#include <sys/file.h>
#include <sys/termios.h>
#include <sys/termio.h>
#include <sys/ttold.h>
#include <sys/stropts.h>
#include <sys/stream.h>
#include <sys/tty.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sundev/vuid_event.h>
#include <sundev/msreg.h>
#include <sundev/msio.h>
/*
* Note: We use spl5 for the mouse because it is functionally the
* same as spl6 and the tty mechanism is using spl5. The original
* code that was doing its own select processing was using spl6.
*/
#define spl_ms spl5
#define ABS(x) ((x) < 0 ? -(x) : (x))
#define BYTECLIP(x) (char)((x) > 127 ? 127 : ((x) < -128 ? -128 : (x)))
struct msdata {
struct ms_softc msd_softc;
queue_t *msd_readq; /* upstream read queue */
mblk_t *msd_iocpending; /* "ioctl" awaiting buffer */
int msd_iocid; /* ID of "ioctl" being waited for */
int msd_iocerror; /* error return from "ioctl" */
int msd_rbufcid; /* ID of pending read-side bufcall */
int msd_wbufcid; /* ID of pending write-side bufcall */
int msd_flags; /* random flags */
short msd_xerox; /* 1 if a Xerox mouse */
char msd_oldbutt; /* button state at last sample */
short msd_state; /* state counter for input routine */
short msd_jitter;
int msd_baud_rate; /* mouse baud rate */
int msd_rcnt_baud_chng; /* baud changed recently */
int msd_data_pkt_cnt; /* no of pkts since last baud change */
int msd_qenable_more; /* enable msrserv if baud chgd */
int msd_hold_baud_stup; /* # of pkts to wait for baud setup */
};
/*
* Values for msd_flags field:
*/
#define MS_OPEN 0x00000001 /* mouse is open for business */
#define MS_IOCWAIT 0x00000002 /* open waiting for ioctl to finish */
#define MS_IOCTOSS 0x00000004 /* Toss ioctl returns */
/*
* Input routine states. See msinput().
*/
#define MS_WAIT_BUTN 0
#define MS_WAIT_X 1
#define MS_WAIT_Y 2
#define MS_WAIT_X2 3
#define MS_WAIT_Y2 4
/*
* This module supports mice runing at 1200, 4800 and 9600 baud rates.
*
* If there was a baud change recently, then we want to wait
* for some time to make sure that no other baud change is on its way.
* If the second baud rate change is done then the packets between
* changes are garbage and are thrown away during the baud change.
*/
/*
* The following #defines were tuned by experimentations.
*/
#define MS_HOLD_BAUD_STUP 48
#define MS_CNT_TOB1200 7
int ms_overrun_msg; /* Message when overrun circular buffer */
int ms_overrun_cnt; /* Increment when overrun circular buffer */
/*
* Max pixel delta of jitter controlled. As this number increases the jumpiness
* of the ms increases, i.e., the coarser the motion for medium speeds.
*/
int ms_jitter_thresh = 0;
/*
* ms_jitter_thresh is the maximum number of jitters suppressed. Thus,
* hz/ms_jitter_thresh is the maximum interval of jitters suppressed. As
* ms_jitter_thresh increases, a wider range of jitter is suppressed. However,
* the more inertia the mouse seems to have, i.e., the slower the mouse is to
* react.
*/
/*
* Measure how many (ms_speed_count) ms deltas exceed threshold
* (ms_speedlimit). If ms_speedlaw then throw away deltas over ms_speedlimit.
* This is to keep really bad mice that jump around from getting too far.
*/
int ms_speedlimit = 48;
int ms_speedlaw = 0;
int ms_speed_count;
int msjitterrate = 12;
extern int hz;
#define JITTER_TIMEOUT (hz/msjitterrate)
int msjittertimeout; /* Timeout used when mstimeout in effect */
/*
* Mouse buffer size in bytes. Place here as variable so that one could
* massage it using adb if it turns out to be too small.
*/
int MS_BUF_BYTES = 4096;
int MS_DEBUG;
/*
* Most of these should be "void", but the people who defined the "streams"
* data structures for S5 didn't understand data types.
*/
static int msopen(/*queue_t *q, int dev, int oflag, int sflag*/);
static int msclose(/*queue_t *q*/);
static int mswput(/*queue_t *q, mblk_t *mp*/);
static int msrput(/*queue_t *q, mblk_t *mp*/);
static int msrserv(/*queue_t *q*/);
static struct module_info msmiinfo = {
0,
"ms",
0,
INFPSZ,
2048,
128
};
static struct qinit msrinit = {
msrput,
msrserv,
msopen,
msclose,
NULL,
&msmiinfo
};
static struct module_info msmoinfo = {
0,
"ms",
0,
INFPSZ,
2048,
128
};
static struct qinit mswinit = {
mswput,
NULL,
msopen,
msclose,
NULL,
&msmoinfo
};
struct streamtab ms_info = {
&msrinit,
&mswinit,
NULL,
NULL,
NULL
};
static int msresched(/*long msdptr*/);
static int msreioctl(/*long msdptr*/);
static void msioctl(/*queue_t *q, mblk_t *mp*/);
static int ms_getparms(/*register Ms_parms *data*/);
static int ms_setparms(/*register Ms_parms *data*/);
static void msflush(/*struct msdata *msd*/);
static void msinput(/*struct msdata *msd, char c*/);
static int msincr(/*struct msdata *msd*/);
/*
* Open a mouse.
*/
/*ARGSUSED*/
static int
msopen(q, dev, oflag, sflag)
queue_t *q;
int dev, oflag, sflag;
{
register struct mousebuf *b;
register struct ms_softc *ms;
register struct msdata *msd;
mblk_t *mp;
mblk_t *datap;
register struct iocblk *iocb;
register struct termios *cb;
if (q->q_ptr != NULL)
return (0); /* already attached */
if (sflag != MODOPEN)
return (OPENFAIL);
/*
* Allocate an msdata structure.
*/
msd = (struct msdata *)new_kmem_zalloc(
sizeof (struct msdata), KMEM_SLEEP);
/*
* Set up queue pointers, so that the "put" procedure will accept
* the reply to the "ioctl" message we send down.
*/
q->q_ptr = (caddr_t)msd;
WR(q)->q_ptr = (caddr_t)msd;
/*
* Setup tty modes.
*/
if ((mp = allocb(sizeof (struct iocblk), BPRI_HI)) == NULL) {
if (strwaitbuf(sizeof (struct iocblk), BPRI_HI, 1))
return (OPENFAIL);
}
if ((datap = allocb(sizeof (struct termios), BPRI_HI)) == NULL) {
if (strwaitbuf(sizeof (struct termios), BPRI_HI, 1)) {
freemsg(mp);
return (OPENFAIL);
}
}
iocb = (struct iocblk *)mp->b_wptr;
iocb->ioc_cmd = TCSETSF;
iocb->ioc_uid = 0;
iocb->ioc_gid = 0;
iocb->ioc_id = getiocseqno();
iocb->ioc_count = sizeof (struct iocblk);
iocb->ioc_error = 0;
iocb->ioc_rval = 0;
mp->b_wptr += (sizeof *iocb)/(sizeof *datap->b_wptr);
mp->b_datap->db_type = M_IOCTL;
cb = (struct termios *)datap->b_wptr;
cb->c_iflag = 0;
cb->c_oflag = 0;
cb->c_cflag = CREAD|CS8|B9600;
cb->c_lflag = 0;
cb->c_line = 0;
bzero((caddr_t)cb->c_cc, NCCS);
datap->b_wptr += (sizeof *cb)/(sizeof *datap->b_wptr);
datap->b_datap->db_type = M_DATA;
mp->b_cont = datap;
msd->msd_flags |= MS_IOCWAIT; /* indicate that we're waiting for */
msd->msd_iocid = iocb->ioc_id; /* this response */
msd->msd_baud_rate = B9600;
msd->msd_rcnt_baud_chng = 1;
msd->msd_data_pkt_cnt = 0;
msd->msd_qenable_more = 0;
msd->msd_hold_baud_stup = MS_HOLD_BAUD_STUP;
putnext(WR(q), mp);
/*
* Now wait for it. Let our read queue put routine wake us up
* when it arrives.
*/
while (msd->msd_flags & MS_IOCWAIT) {
if (sleep((caddr_t)&msd->msd_iocerror, STOPRI|PCATCH)) {
u.u_error = EINTR;
goto error;
}
}
if (u.u_error = msd->msd_iocerror)
goto error;
/*
* Set up private data.
*/
msd->msd_state = MS_WAIT_BUTN;
msd->msd_readq = q;
msd->msd_iocpending = NULL;
ms = &msd->msd_softc;
/*
* Allocate buffer and initialize data.
*/
if (ms->ms_buf == 0) {
ms->ms_bufbytes = MS_BUF_BYTES;
b = (struct mousebuf *)new_kmem_zalloc(
(u_int)ms->ms_bufbytes, KMEM_SLEEP);
b->mb_size = 1 + (ms->ms_bufbytes - sizeof (struct mousebuf))
/ sizeof (struct mouseinfo);
ms->ms_buf = b;
ms->ms_vuidaddr = VKEY_FIRST;
msjittertimeout = JITTER_TIMEOUT;
msflush(msd);
}
msd->msd_flags = MS_OPEN;
/*
* Tell the module below us that it should return input immediately.
*/
(void) putctl1(WR(q)->q_next, M_CTL, MC_SERVICEIMM);
return (0);
error:
/*
* Free dynamically allocated resources.
*/
if (ms->ms_buf != NULL)
kmem_free((caddr_t)ms->ms_buf, (u_int)ms->ms_bufbytes);
kmem_free((caddr_t)msd, sizeof (*msd));
return (OPENFAIL);
}
/*
* Close the mouse
*/
static int
msclose(q)
queue_t *q;
{
register struct msdata *msd = (struct msdata *)q->q_ptr;
register struct ms_softc *ms;
/*
* Tell the module below us that it need not return input immediately.
*/
(void) putctl1(q->q_next, M_CTL, MC_SERVICEDEF);
/*
* Since we're about to destroy our private data, turn off
* our open flag first, so we don't accept any more input
* and try to use that data.
*/
msd->msd_flags = 0;
if (msd->msd_iocpending != NULL) {
/*
* We were holding an "ioctl" response pending the
* availability of an "mblk" to hold data to be passed up;
* another "ioctl" came through, which means that "ioctl"
* must have timed out or been aborted.
*/
freemsg(msd->msd_iocpending);
msd->msd_iocpending = NULL;
}
/*
* Cancel outstanding bufcall requests.
*/
if (msd->msd_rbufcid)
unbufcall(msd->msd_rbufcid);
if (msd->msd_wbufcid)
unbufcall(msd->msd_wbufcid);
ms = &msd->msd_softc;
/* Free mouse buffer */
if (ms->ms_buf != NULL)
kmem_free((caddr_t)ms->ms_buf, (u_int)ms->ms_bufbytes);
/* Free msdata structure */
kmem_free((caddr_t)msd, sizeof (*msd));
}
/*
* Read queue service routine.
* Turn buffered mouse events into stream messages.
*/
static int
msrserv(q)
register queue_t *q;
{
struct msdata *msd = (struct msdata *)q->q_ptr;
register struct ms_softc *ms;
register struct mousebuf *b;
register struct mouseinfo *mi;
register int button_number;
register int hwbit, pri;
mblk_t *bp;
ms = &msd->msd_softc;
b = ms->ms_buf;
pri = spl_ms();
if (MS_DEBUG)
printf("msrserv: start\n");
if (msd->msd_rcnt_baud_chng && ms->ms_oldoff != b->mb_off) {
int no_pkt = b->mb_off - ms->ms_oldoff;
int i;
no_pkt = no_pkt > 0 ? no_pkt : (b->mb_size - no_pkt);
if (no_pkt < msd->msd_hold_baud_stup) {
msd->msd_qenable_more = 1;
return;
} else {
/*
* throw away packets in beginning (mostly garbage)
*/
for (i = 0; i < msd->msd_hold_baud_stup; i++) {
ms->ms_oldoff++; /* next event */
/* circular buffer wraparound */
if (ms->ms_oldoff >= b->mb_size)
ms->ms_oldoff = 0;
}
msd->msd_rcnt_baud_chng = 0;
msd->msd_data_pkt_cnt = 0;
msd->msd_qenable_more = 0;
}
}
while (canput(q->q_next) && ms->ms_oldoff != b->mb_off) {
mi = &b->mb_info[ms->ms_oldoff];
switch (ms->ms_readformat) {
case MS_3BYTE_FORMAT: {
register char *cp;
if ((bp = allocb(3, BPRI_HI)) != NULL) {
cp = (char *)bp->b_wptr;
*cp++ = 0x80 | mi->mi_buttons;
/* Update read buttons */
ms->ms_prevbuttons = mi->mi_buttons;
*cp++ = mi->mi_x;
*cp++ = -mi->mi_y;
/* lower pri to avoid mouse droppings */
(void) splx(pri);
bp->b_wptr = (u_char *)cp;
putnext(q, bp);
pri = spl_ms();
} else {
/*
* Arrange to try again later.
*/
msd->msd_rbufcid = bufcall(3, BPRI_HI, msresched, (long)msd);
if (msd->msd_rbufcid != 0)
return;
/* bufcall failed; just pitch this event */
/* or maybe flush queue? */
}
ms->ms_oldoff++; /* next event */
if (ms->ms_oldoff >= b->mb_size)
ms->ms_oldoff = 0; /* circular buffer wraparound */
break;
}
case MS_VUID_FORMAT: {
register Firm_event *fep;
bp = NULL;
switch (ms->ms_eventstate) {
case EVENT_X:
/*
* Send x if changed.
*/
if (mi->mi_x != 0) {
if ((bp = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
fep = (Firm_event *)bp->b_wptr;
fep->id = vuid_id_addr(ms->ms_vuidaddr) |
vuid_id_offset(LOC_X_DELTA);
fep->pair_type = FE_PAIR_ABSOLUTE;
fep->pair = LOC_X_ABSOLUTE;
fep->value = mi->mi_x;
fep->time = mi->mi_time;
} else {
/*
* Arrange to try again later.
*/
msd->msd_rbufcid = bufcall(sizeof (Firm_event), BPRI_HI,
msresched, (long)msd);
if (msd->msd_rbufcid != 0)
return;
/* bufcall failed; just pitch this event */
/* or maybe flush queue? */
ms->ms_eventstate = EVENT_BUT3;
}
}
break;
case EVENT_Y:
/*
* Send y if changed.
*/
if (mi->mi_y != 0) {
if ((bp = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
fep = (Firm_event *)bp->b_wptr;
fep->id = vuid_id_addr(ms->ms_vuidaddr) |
vuid_id_offset(LOC_Y_DELTA);
fep->pair_type = FE_PAIR_ABSOLUTE;
fep->pair = LOC_Y_ABSOLUTE;
fep->value = -mi->mi_y;
fep->time = mi->mi_time;
} else {
/*
* Arrange to try again later.
*/
msd->msd_rbufcid = bufcall(sizeof (Firm_event), BPRI_HI,
msresched, (long)msd);
if (msd->msd_rbufcid != 0)
return;
/* bufcall failed; just pitch this event */
/* or maybe flush queue? */
ms->ms_eventstate = EVENT_BUT3;
}
}
break;
case EVENT_BUT1:
case EVENT_BUT2:
case EVENT_BUT3:
/*
* Test the button, and send an event for it if it changed.
*/
button_number = ms->ms_eventstate - EVENT_BUT1;
hwbit = MS_HW_BUT1 >> button_number;
if ((ms->ms_prevbuttons & hwbit) != (mi->mi_buttons & hwbit)) {
if ((bp = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
fep = (Firm_event *)bp->b_wptr;
fep->id = vuid_id_addr(ms->ms_vuidaddr) |
vuid_id_offset(BUT(1) + button_number);
fep->pair_type = FE_PAIR_NONE;
fep->pair = 0;
/* Update read buttons and set value */
if (mi->mi_buttons & hwbit) {
fep->value = 0;
ms->ms_prevbuttons |= hwbit;
} else {
fep->value = 1;
ms->ms_prevbuttons &= ~hwbit;
}
fep->time = mi->mi_time;
} else {
/*
* Arrange to try again later.
*/
msd->msd_rbufcid = bufcall(sizeof (Firm_event), BPRI_HI,
msresched, (long)msd);
if (msd->msd_rbufcid != 0)
return;
/* bufcall failed; just pitch this event */
/* or maybe flush queue? */
ms->ms_eventstate = EVENT_BUT3;
}
}
break;
}
if (bp != NULL) {
/* lower pri to avoid mouse droppings */
(void) splx(pri);
bp->b_wptr += sizeof (Firm_event);
putnext(q, bp);
pri = spl_ms();
}
if (ms->ms_eventstate == EVENT_BUT3) {
ms->ms_eventstate = EVENT_X;
ms->ms_oldoff++; /* next event */
if (ms->ms_oldoff >= b->mb_size)
ms->ms_oldoff = 0; /* circular buffer wraparound */
} else
ms->ms_eventstate++;
}
}
}
}
static int
msresched(msdptr)
long msdptr;
{
register queue_t *q;
register struct msdata *msd = (struct msdata *)msdptr;
/*
* The bufcall that led us here is no longer pending.
*/
msd->msd_rbufcid = 0;
if ((q = msd->msd_readq) != 0)
qenable(q); /* run the service procedure */
}
/*
* Line discipline output queue put procedure: handles M_IOCTL
* messages.
*/
static int
mswput(q, mp)
register queue_t *q;
register mblk_t *mp;
{
/*
* Process M_FLUSH, and some M_IOCTL, messages here; pass
* everything else down.
*/
switch (mp->b_datap->db_type) {
case M_FLUSH:
if (*mp->b_rptr & FLUSHW)
flushq(q, FLUSHDATA);
if (*mp->b_rptr & FLUSHR)
flushq(RD(q), FLUSHDATA);
default:
putnext(q, mp); /* pass it down the line */
break;
case M_IOCTL:
msioctl(q, mp);
break;
}
}
static int
msreioctl(msdptr)
long msdptr;
{
struct msdata *msd = (struct msdata *)msdptr;
register queue_t *q;
register mblk_t *mp;
/*
* The bufcall that led us here is no longer pending.
*/
msd->msd_wbufcid = 0;
if ((q = msd->msd_readq) == 0)
return;
if ((mp = msd->msd_iocpending) != NULL) {
msd->msd_iocpending = NULL; /* not pending any more */
msioctl(WR(q), mp);
}
}
static void
msioctl(q, mp)
register queue_t *q;
register mblk_t *mp;
{
struct msdata *msd;
register struct ms_softc *ms;
register struct iocblk *iocp;
caddr_t data;
Vuid_addr_probe *addr_probe;
u_int ioctlrespsize;
int pri;
int err = 0;
msd = (struct msdata *)q->q_ptr;
if (msd == 0) {
err = EINVAL;
goto out;
}
ms = &msd->msd_softc;
iocp = (struct iocblk *)mp->b_rptr;
if (mp->b_cont != NULL)
data = (caddr_t)mp->b_cont->b_rptr;
if (MS_DEBUG)
printf("mswput(M_IOCTL, %X, %X)\n", iocp->ioc_cmd, data);
switch (iocp->ioc_cmd) {
case VUIDSFORMAT:
if (*(int *) data == ms->ms_readformat)
break;
ms->ms_readformat = *(int *) data;
/*
* Flush mouse buffer because the messages upstream of us are in
* the old format.
*/
msflush(msd);
break;
case VUIDGFORMAT: {
register mblk_t *datap;
if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
ioctlrespsize = sizeof (int);
goto allocfailure;
}
*(int *)datap->b_wptr = ms->ms_readformat;
datap->b_wptr += sizeof (int);
mp->b_cont = datap;
iocp->ioc_count = sizeof (int);
break;
}
case VUIDSADDR:
addr_probe = (Vuid_addr_probe *) data;
if (addr_probe->base != VKEY_FIRST) {
err = ENODEV;
break;
}
ms->ms_vuidaddr = addr_probe->data.next;
break;
case VUIDGADDR:
addr_probe = (Vuid_addr_probe *) data;
if (addr_probe->base != VKEY_FIRST) {
err = ENODEV;
break;
}
addr_probe->data.current = ms->ms_vuidaddr;
break;
case MSIOGETBUF: {
register mblk_t *datap;
if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
ioctlrespsize = sizeof (int);
goto allocfailure;
}
*(int *)datap->b_wptr = (int) ms->ms_buf;
datap->b_wptr += sizeof (int);
mp->b_cont = datap;
iocp->ioc_count = sizeof (int);
break;
}
case MSIOGETPARMS: {
register mblk_t *datap;
if (MS_DEBUG)
printf("ms_getparms\n");
if ((datap = allocb(sizeof (Ms_parms), BPRI_HI)) == NULL) {
ioctlrespsize = sizeof (Ms_parms);
goto allocfailure;
}
err = ms_getparms((Ms_parms *)datap->b_wptr);
datap->b_wptr += sizeof (Ms_parms);
mp->b_cont = datap;
iocp->ioc_count = sizeof (Ms_parms);
break;
}
case MSIOSETPARMS:
if (MS_DEBUG)
printf("ms_setparms\n");
err = ms_setparms((Ms_parms *)data);
break;
default:
putnext(q, mp); /* pass it down the line */
return;
}
out:
if (err != 0) {
iocp->ioc_rval = 0;
iocp->ioc_error = err;
mp->b_datap->db_type = M_IOCNAK;
} else {
iocp->ioc_rval = 0;
iocp->ioc_error = 0; /* brain rot */
mp->b_datap->db_type = M_IOCACK;
}
qreply(q, mp);
return;
allocfailure:
/*
* We needed to allocate something to handle this "ioctl", but
* couldn't; save this "ioctl" and arrange to get called back when
* it's more likely that we can get what we need.
* If there's already one being saved, throw it out, since it
* must have timed out.
*/
pri = splstr();
if (msd->msd_iocpending != NULL)
freemsg(msd->msd_iocpending);
msd->msd_iocpending = mp;
if (msd->msd_wbufcid)
unbufcall(msd->msd_wbufcid);
msd->msd_wbufcid = bufcall(ioctlrespsize, BPRI_HI, msreioctl, (long)msd);
(void) splx(pri);
return;
}
static int
ms_getparms(data)
register Ms_parms *data;
{
data->jitter_thresh = ms_jitter_thresh;
data->speed_law = ms_speedlaw;
data->speed_limit = ms_speedlimit;
return (0);
}
static int
ms_setparms(data)
register Ms_parms *data;
{
ms_jitter_thresh = data->jitter_thresh;
ms_speedlaw = data->speed_law;
ms_speedlimit = data->speed_limit;
return (0);
}
static void
msflush(msd)
register struct msdata *msd;
{
register struct ms_softc *ms = &msd->msd_softc;
int s = spl_ms();
register queue_t *q;
ms->ms_oldoff = 0;
ms->ms_eventstate = EVENT_X;
ms->ms_buf->mb_off = 0;
ms->ms_prevbuttons = MS_HW_BUT1 | MS_HW_BUT2 | MS_HW_BUT3;
msd->msd_oldbutt = ms->ms_prevbuttons;
if ((q = msd->msd_readq) != NULL && (q = q->q_next) != NULL)
(void) putctl1(q, M_FLUSH, FLUSHR);
(void) splx(s);
}
/*
* Mouse read queue put procedure.
*/
static int
msrput(q, mp)
register queue_t *q;
register mblk_t *mp;
{
register struct msdata *msd = (struct msdata *)q->q_ptr;
register mblk_t *bp;
register char *readp;
register mblk_t *imp;
register mblk_t* datap;
register struct iocblk *iocb;
register struct termios *cb;
struct iocblk *iocp;
if (msd == 0)
return;
if (MS_DEBUG)
printf("msrput: start\n");
switch (mp->b_datap->db_type) {
case M_FLUSH:
if (MS_DEBUG)
printf("msrput: M_FLUSH\n");
if (*mp->b_rptr & FLUSHW)
flushq(WR(q), FLUSHDATA);
if (*mp->b_rptr & FLUSHR)
flushq(q, FLUSHDATA);
default:
putnext(q, mp);
return;
case M_BREAK:
if (MS_DEBUG)
printf("msrput: received a break\n");
if (msd->msd_rcnt_baud_chng && msd->msd_data_pkt_cnt == 0) {
freemsg(mp);
return;
}
/*
* If we are sampling a 4800 baud mouse at 9600,
* we want to wait for long time because there is no
* fixed timeframe for receiving break. If we are sampling
* a 1200 baud mouse at 4800 or 9600 baud rate then
* it is guaranteed that break will be received very soon.
*/
if (msd->msd_rcnt_baud_chng) {
switch (msd->msd_baud_rate) {
case B9600:
msd->msd_hold_baud_stup = MS_HOLD_BAUD_STUP/2;
msd->msd_baud_rate = B4800;
break;
case B4800:
if (msd->msd_data_pkt_cnt <= MS_CNT_TOB1200) {
msd->msd_hold_baud_stup = MS_HOLD_BAUD_STUP/6;
msd->msd_baud_rate = B1200;
} else {
msd->msd_hold_baud_stup = MS_HOLD_BAUD_STUP;
msd->msd_baud_rate = B9600;
}
break;
case B1200:
default:
msd->msd_hold_baud_stup = MS_HOLD_BAUD_STUP;
msd->msd_baud_rate = B9600;
break;
}
} else {
msd->msd_hold_baud_stup = MS_HOLD_BAUD_STUP;
msd->msd_baud_rate = B9600;
}
/*
* Change baud rate
*/
if ((imp = allocb(sizeof (struct iocblk), BPRI_HI)) == NULL) {
return;
}
if ((datap = allocb(sizeof (struct termios), BPRI_HI)) == NULL) {
freemsg(imp);
return;
}
/* set up ioctl structure */
iocb = (struct iocblk *)imp->b_wptr;
iocb->ioc_cmd = TCSETSF;
iocb->ioc_uid = 0;
iocb->ioc_gid = 0;
iocb->ioc_id = getiocseqno();
iocb->ioc_count = sizeof (struct iocblk);
iocb->ioc_error = 0;
iocb->ioc_rval = 0;
imp->b_wptr += (sizeof (*iocb))/(sizeof (*datap->b_wptr));
imp->b_datap->db_type = M_IOCTL;
cb = (struct termios *)datap->b_wptr;
cb->c_iflag = 0;
cb->c_oflag = 0;
cb->c_cflag = CREAD|CS8|msd->msd_baud_rate;
cb->c_lflag = 0;
bzero((caddr_t)cb->c_cc, NCCS);
datap->b_wptr += (sizeof (*cb))/(sizeof (*datap->b_wptr));
datap->b_datap->db_type = M_DATA;
imp->b_cont = datap;
msd->msd_flags |= MS_IOCTOSS|MS_IOCWAIT;
msd->msd_iocid = iocb->ioc_id;
msflush(msd);
flushq(q, FLUSHALL);
putnext(WR(q), imp);
freemsg(mp);
msd->msd_rcnt_baud_chng = 1;
msd->msd_data_pkt_cnt = 0;
if (MS_DEBUG)
printf("baud %X\n", msd->msd_baud_rate);
return;
case M_IOCACK:
case M_IOCNAK:
if (MS_DEBUG)
printf("msrput: ioctl\n");
/*
* If we are doing an "ioctl" ourselves, check if this
* is the reply to that code. If so, wake up the
* "open" routine, and toss the reply, otherwise just
* pass it up.
*/
iocp = (struct iocblk *)mp->b_rptr;
if (!(msd->msd_flags & MS_IOCWAIT) ||
iocp->ioc_id != msd->msd_iocid) {
/*
* This isn't the reply we're looking for. Move along.
*/
putnext(q, mp);
} else {
msd->msd_flags &= ~MS_IOCWAIT;
msd->msd_iocerror = iocp->ioc_error;
/*
* If we sent down a request to change the baud rate,
* this is the reply. Just ignore it.
*/
if (msd->msd_flags & MS_IOCTOSS) {
if (MS_DEBUG)
printf("msrput: got reply from baud rate change\n");
msd->msd_flags &= ~MS_IOCTOSS;
msflush(msd);
flushq(q, FLUSHALL);
}
wakeup((caddr_t)&msd->msd_iocerror);
freemsg(mp);
}
return;
case M_DATA:
if (MS_DEBUG)
printf("msrput: M_DATA\n");
break;
}
/*
* A data message, consisting of bytes from the mouse.
* Hand each byte to our input routine.
*/
bp = mp;
do {
readp = (char *)bp->b_rptr;
while (readp < (char *)bp->b_wptr) {
if (msd->msd_rcnt_baud_chng)
msd->msd_data_pkt_cnt++;
msinput(msd, *readp++);
}
bp->b_rptr = (unsigned char *)readp;
} while ((bp = bp->b_cont) != NULL); /* next block, if any */
freemsg(mp);
}
/*
* Mouse input routine; process a byte received from a mouse and
* assemble into a mouseinfo message for the window system.
* Handles both XEROX mice and Mouse Systems mice.
*
* The MSC mice send a five-byte packet organized as
* button, dx, dy, dx, dy
* where dx and dy can be any signed byte value. The mouseinfo message
* is organized as
dx, dy, button, timestamp
* Our strategy, then, is to split the MSC packet into two mouseinfo
* messages, retaining the button information for the second message.
*
* Xerox mice are similar but the packet is only three bytes long:
* button, dx, dy
* Xerox mice have button byte 0x88; MSC mice have button byte
* 0x80, both with button values in low 3 bits. We'll use this to
* distinguish between them.
*
* Basic algorithm: throw away bytes until we get a [potential]
* button byte. Collect button, dx, dy, and send. MSC mouse?
* Save button, collect new dx, dy, and send. Repeat.
*
* Watch out for overflow!
*/
static void
msinput(msd, c)
register struct msdata *msd;
char c;
{
register struct ms_softc *ms;
register struct mousebuf *b;
register struct mouseinfo *mi;
register int jitter_radius;
register int temp;
ms = &msd->msd_softc;
b = ms->ms_buf;
if (b == NULL)
return;
mi = &b->mb_info[b->mb_off];
switch (msd->msd_state) {
case MS_WAIT_BUTN:
if ((c & 0xf0) != 0x80) {
if (MS_DEBUG)
printf("Mouse input char %x discarded\n", (int) c & 0xff);
if (msd->msd_rcnt_baud_chng) {
msflush(msd);
flushq(msd->msd_readq, FLUSHALL);
msd->msd_hold_baud_stup++;
}
return;
}
/*
* Probably a button byte. Lower 3 bits are left, middle, right.
* We're going to try to use the allegation that Xerox mice set bit 3
* (0x08) to decide what to do next.
*/
mi->mi_buttons = c & (MS_HW_BUT1 | MS_HW_BUT2 | MS_HW_BUT3);
#ifndef IGNORE_XEROX
msd->msd_xerox = c & 8;
#endif
break;
case MS_WAIT_X:
/*
* Delta X byte. Add the delta X from this sample to the delta X
* we're accumulating in the current event.
*/
temp = (int) (mi->mi_x + c);
mi->mi_x = BYTECLIP(temp);
uniqtime(&mi->mi_time); /* record time when sample arrived */
break;
case MS_WAIT_Y:
/*
* Delta Y byte. Add the delta Y from this sample to the delta Y
* we're accumulating in the current event. (Subtract, actually,
* because the mouse reports increasing Y up the screen.)
*/
temp = (int) (mi->mi_y - c);
mi->mi_y = BYTECLIP(temp);
break;
case MS_WAIT_X2:
/*
* Second delta X byte. Only for MSC mice.
*/
temp = (int) (mi->mi_x + c);
mi->mi_x = BYTECLIP(temp);
uniqtime(&mi->mi_time);
break;
case MS_WAIT_Y2:
/*
* Second delta Y byte. Only for MSC mice.
*/
temp = (int) (mi->mi_y - c);
mi->mi_y = BYTECLIP(temp);
break;
}
/*
* Done yet?
*/
if ((msd->msd_state == MS_WAIT_Y2) ||
(msd->msd_xerox && (msd->msd_state == MS_WAIT_Y)))
msd->msd_state = MS_WAIT_BUTN; /* BONG. Start again. */
else {
msd->msd_state += 1;
return;
}
if (msd->msd_jitter) {
untimeout(msincr, (caddr_t) msd);
msd->msd_jitter = 0;
}
if (mi->mi_buttons == msd->msd_oldbutt) {
/*
* Buttons did not change; did position?
*/
if (mi->mi_x == 0 && mi->mi_y == 0) {
return; /* no, position did not change - boring event */
}
/*
* Did the mouse move more than the jitter threshhold?
*/
jitter_radius = ms_jitter_thresh;
#ifndef IGNORE_XEROX
if (msd->msd_xerox)
/*
* Account for double resolution of xerox mouse.
*/
jitter_radius *= 2;
#endif
if (ABS((int) mi->mi_x) <= jitter_radius &&
ABS((int) mi->mi_y) <= jitter_radius) {
/*
* Mouse moved less than the jitter threshhold. Don't indicate an
* event; keep accumulating motions. After "msjittertimeout"
* ticks expire, treat the accumulated delta as the real delta.
*/
msd->msd_jitter = 1;
timeout(msincr, (caddr_t) msd, msjittertimeout);
return;
}
}
msd->msd_oldbutt = mi->mi_buttons;
msincr(msd);
}
/*
* Increment the mouse sample pointer.
* Called either immediately after a sample or after a jitter timeout.
*/
static int
msincr(msd)
struct msdata *msd;
{
register struct ms_softc *ms = &msd->msd_softc;
register struct mousebuf *b;
register struct mouseinfo *mi;
char oldbutt;
register short xc, yc;
register int wake;
register int speedlimit = ms_speedlimit;
register int xabs, yabs;
int s;
if (MS_DEBUG)
printf("msincr: start\n");
b = ms->ms_buf;
if (b == NULL)
return;
s = spl_ms();
mi = &b->mb_info[b->mb_off];
if (ms_speedlaw) {
#ifndef IGNORE_XEROX
if (msd->msd_xerox)
/*
* Account for double resolution of Xerox mouse.
*/
speedlimit *= 2;
#endif
xabs = ABS((int) mi->mi_x);
yabs = ABS((int) mi->mi_y);
if (xabs > speedlimit || yabs > speedlimit)
ms_speed_count++;
if (xabs > speedlimit)
mi->mi_x = 0;
if (yabs > speedlimit)
mi->mi_y = 0;
}
oldbutt = mi->mi_buttons;
#ifndef IGNORE_XEROX
/*
* XEROX mice are 200/inch; scale to 100/inch.
*/
if (msd->msd_xerox) {
/*
* Xc and yc carry over fractional part. You might think that we have
* to worry about mi->mi_[xy] being negative here, but remember that
* using shift to divide always leaves a positive remainder!
*/
xc = mi->mi_x & 1;
yc = mi->mi_y & 1;
mi->mi_x >>= 1;
mi->mi_y >>= 1;
} else
#endif
xc = yc = 0;
/* See if we need to wake up anyone waiting for input */
wake = b->mb_off == ms->ms_oldoff;
/* Adjust circular buffer pointer */
if (++b->mb_off >= b->mb_size) {
b->mb_off = 0;
mi = b->mb_info;
} else {
mi++;
}
/*
* If over-took read index then flush buffer so that mouse state
* is consistent.
*/
if (b->mb_off == ms->ms_oldoff) {
if (ms_overrun_msg)
printf("Mouse buffer flushed when overrun.\n");
msflush(msd);
ms_overrun_cnt++;
mi = b->mb_info;
}
/* Remember current buttons and fractional part of x & y */
mi->mi_buttons = oldbutt;
mi->mi_x = (char) xc;
mi->mi_y = (char) yc;
if (wake || msd->msd_qenable_more) {
qenable(msd->msd_readq); /* run the service procedure */
}
(void) splx(s);
}