/* * (C) 1984 UniSoft Corp. of Berkeley CA * * UniPlus Source Code. This program is proprietary * with Unisoft Corporation and is not to be reproduced * or used in any manner except as authorized in * writing by Unisoft. * * Mouse Driver */ #include "sys/param.h" #include "sys/config.h" #include "sys/types.h" #include "sys/systm.h" #include "sys/dir.h" #include "sys/signal.h" #include "sys/user.h" #include "sys/proc.h" #include "sys/errno.h" #include "sys/file.h" #include "sys/tty.h" #include "sys/termio.h" #include "sys/conf.h" #include "sys/sysinfo.h" #include "sys/var.h" #include "sys/reg.h" #include "sys/buf.h" #include "setjmp.h" #include "sys/cops.h" #include "sys/local.h" #include "sys/elog.h" #include "sys/ms.h" #include "sys/mouse.h" #include "sys/mmu.h" #include "sys/kb.h" #include "sys/al_ioctl.h" #define splms spl2 /* flags local to ms.c */ char mouseopen; /* active flag */ char msblkd; /* flag to sleep on when blocked */ /* also used in l1.c (vertical retrace interrupt code) */ struct msparms mparm; /* place to save ioctl data */ struct proc *msproc; /* controlling process for mouse */ char msvrmsk; /* mask of low bits of retrace counter */ /* values set in kb.c */ extern char ms_plg, ms_btn; /* mouse plugged-in and button state */ extern short ms_row, ms_col; /* last received row and column */ extern time_t lbolt; #define QUELEN 128 typedef unsigned long mem_t; int mqlen; mem_t *mqlo, *mqhi; /* high and low pointers into ... */ mem_t mqbuf[QUELEN]; /* ring buffer for mouse data */ mem_t mtim[QUELEN]; msopen(dev, flag) dev_t dev; { if (dev != 0) { /* minor device number is wrong */ u.u_error = ENXIO; return; } if (ms_plg) { /* mouse is not plugged in */ u.u_error = ENODEV; return; } if (flag != 1) { /* open for writing !! */ u.u_error = EINVAL; return; } if (u.u_ttyd != CONSOLE) { /* Controlling tty not bitmap */ u.u_error = EPERM; return; } if (mouseopen++ > 0) { /* already opened */ u.u_error = EBUSY; return; } splms(); msproc = u.u_procp; mqhi = mqlo = mqbuf; mqlen = 0; mparm.mp_irate = 28; mparm.mp_fdlay = 300; mparm.mp_flags = MF_BUT; l2copscmd(MOUSEON); spl0(); } /* * Reset everything since code elsewhere (in l1.c) uses it. */ /* ARGSUSED */ msclose(dev, flag) { if (mouseopen <= 0) u.u_error = EINVAL; else { SPL6(); mouseopen = 0; /* only accessed in ms.c */ mqhi = mqlo = mqbuf; mqlen = 0; mparm.mp_irate = 0; mparm.mp_fdlay = 0; mparm.mp_flags = 0; msvrmsk = 0; l2copscmd(MOUSEOFF); SPL0(); } } msstrategy(bp) register struct buf *bp; { register mem_t *rp; /* reciever buffer pointer */ register int i; /* record count */ /* Make sure the mouse is plugged in and the read request is for a * multiple of the record size. */ if (ms_plg) { /* mouse unplugged */ u.u_error = ENODEV; goto fail; } if (bp->b_bcount & 3) { /* count not multiple of record size */ u.u_error = EINVAL; fail: bp->b_resid = bp->b_bcount; iodone(bp); return; } if (mqlo == mqhi) { /* queue empty */ if ((int)mparm.mp_irate <= 0) /* mouse shutdown */ u.u_error = EIO; splms(); if (mparm.mp_flags & MF_BLK) { /* block till record avail */ msblkd = 1; while (msblkd) (void) sleep((caddr_t)&msblkd, TTIPRI); goto ok; } spl0(); goto fail; } splms(); /* so msintr doesnt screw up que ptrs */ ok: if (lbolt - mtim[mqlo-mqbuf] >= mparm.mp_fdlay) { if (mparm.mp_fdlay) msintr(M_FLUSH); } rp = (mem_t *)bp->b_un.b_addr; /* start of receiver buffer */ for (i=bp->b_bcount; i>0 && mqlo != mqhi; i -= 4) { *rp++ = *mqlo++; if (mqlo >= mqbuf + QUELEN) mqlo = mqbuf; } bp->b_resid = i; mqlen -= (bp->b_bcount - i) >> 2; spl0(); iodone(bp); return; } struct buf rmsbuf; /* Buffer for raw input-output */ msread(dev) { if (msproc != u.u_procp) { u.u_error = EIO; return; } rmsbuf.b_flags &= ~B_BUSY; physio(msstrategy, &rmsbuf, dev, B_READ); } msintr(kind) { register struct msrecord *mp; union { struct msrecord mf_rec; unsigned long mf_long; } msr; if (!mouseopen || mparm.mp_irate == 0) {/* mouse not active */ return; } if (ms_plg) { mqlo = mqhi = mqbuf; mqlen = 0; return; } msr.mf_long = 0; /* clear new record */ mp = &msr.mf_rec; /* get pointer to record structure */ switch (kind) { /* kind of interrupt */ case M_FLUSH: /* auto flush (called from msintr,msstrategy) */ mp->mr_but = 1; case M_PLUG: /* automatic reset (called from kbintr) */ mp->mr_reset = 1; mqlo = mqhi = mqbuf; mqlen = 1; mtim[0] = lbolt; *mqhi++ = msr.mf_long; return; case M_BUT: /* mouse button changed (called from kbintr) */ if ((mparm.mp_flags & MF_BUT) == 0) return; break; case M_CTL: /* control key changed (called from kbintr) */ if ((mparm.mp_flags & MF_CTL) == 0) return; break; case M_SFT: /* shift key changed (called from kbintr) */ if ((mparm.mp_flags & MF_SFT) == 0) return; break; } if (mqlen) { /* check for invalid queue data */ if (lbolt - mtim[mqlo-mqbuf] >= mparm.mp_fdlay) { if (mparm.mp_fdlay) msintr(M_FLUSH); } if (mqlen >= QUELEN) return; } else { /* queue was empty */ if (mparm.mp_flags & MF_SIG) psignal(msproc, SIGMOUS); } mp->mr_but = ms_btn ? 1 : 0; mp->mr_ctl = kb_ctrl ? 1 : 0; mp->mr_sft = kb_shft ? 1 : 0; mp->mr_time = lbolt & 0xFFF; if (kind == M_MOVE) { /* called from kbintr */ mp->mr_row = ms_row; mp->mr_col = ms_col; } mtim[mqhi - mqbuf] = lbolt; *mqhi++ = msr.mf_long; mqlen++; if (mqhi >= mqbuf + QUELEN) mqhi = mqbuf; if (msblkd) { msblkd = 0; wakeup((caddr_t)&msblkd); } } /* ARGSUSED */ msioctl(dev, cmd, addr, flag) dev_t dev; int cmd; caddr_t addr; int flag; { register struct msparms *mp = &mparm; int dlay, rate; switch (cmd) { case AL_GMOUSE: if (mp->mp_qlen = mqlen) { mp->mp_otime = lbolt - mtim[mqlo-mqbuf]; mp->mp_ytime = lbolt - mtim[mqhi-mqbuf-1]; } else { mp->mp_otime = 0; mp->mp_ytime = 0; } if (copyout((char *)mp, addr, sizeof(struct msparms))) u.u_error = EFAULT; break; case AL_SMOUSE: dlay = mp->mp_fdlay; rate = mp->mp_irate; if (copyin(addr, (char *)mp, sizeof(struct msparms))) u.u_error = EFAULT; else { if (mp->mp_fdlay) { if (mp->mp_fdlay < 20) { splms(); mp->mp_fdlay = dlay; /* restore */ mqlen = 0; mqhi = mqlo = mqbuf; spl0(); } else if (mp->mp_fdlay > 4095) mp->mp_fdlay = 4095; } if (mp->mp_irate != rate) { /* did int rate chg */ mp->mp_irate = (mp->mp_irate + 3) & ~3; if (mp->mp_irate > 28) mp->mp_irate = 28; splms(); if (mp->mp_irate) l2copscmd((char)((MOUSEON&~7)|(mp->mp_irate>>2))); else l2copscmd(MOUSEOFF); spl0(); } splms(); if (mp->mp_flags & MF_VRT) msvrmsk = mp->mp_flags & MF_VRATE; spl0(); } break; default: u.u_error = ENOTTY; } }