mse.c revision 10624
1637Snate/* 2637Snate * Copyright 1992 by the University of Guelph 3637Snate * 4637Snate * Permission to use, copy and modify this 5637Snate * software and its documentation for any purpose and without 6637Snate * fee is hereby granted, provided that the above copyright 7637Snate * notice appear in all copies and that both that copyright 8637Snate * notice and this permission notice appear in supporting 9637Snate * documentation. 10637Snate * University of Guelph makes no representations about the suitability of 11637Snate * this software for any purpose. It is provided "as is" 12637Snate * without express or implied warranty. 131817Sdg * 1410624Sbde * $Id: mse.c,v 1.13 1995/07/16 10:12:06 bde Exp $ 15637Snate */ 16637Snate/* 17637Snate * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and 18637Snate * the X386 port, courtesy of 19637Snate * Rick Macklem, rick@snowhite.cis.uoguelph.ca 20637Snate * Caveats: The driver currently uses spltty(), but doesn't use any 21637Snate * generic tty code. It could use splmse() (that only masks off the 22637Snate * bus mouse interrupt, but that would require hacking in i386/isa/icu.s. 23637Snate * (This may be worth the effort, since the Logitech generates 30/60 24637Snate * interrupts/sec continuously while it is open.) 25637Snate * NB: The ATI has NOT been tested yet! 26637Snate */ 27637Snate 28637Snate/* 29637Snate * Modification history: 304259Sjkh * Sep 6, 1994 -- Lars Fredriksen(fredriks@mcs.com) 314259Sjkh * improved probe based on input from Logitech. 32637Snate * 33637Snate * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu) 34637Snate * fixes to make it work with Microsoft InPort busmouse 35637Snate * 36637Snate * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu) 37637Snate * added patches for new "select" interface 38637Snate * 39637Snate * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu) 40637Snate * changed position of some spl()'s in mseread 41637Snate * 42637Snate * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu) 43637Snate * limit maximum negative x/y value to -127 to work around XFree problem 44637Snate * that causes spurious button pushes. 45637Snate */ 46637Snate 47637Snate#include "mse.h" 48637Snate#if NMSE > 0 492056Swollman#include <sys/param.h> 503745Swollman#include <sys/systm.h> 512056Swollman#include <sys/proc.h> 522056Swollman#include <sys/user.h> 532056Swollman#include <sys/buf.h> 542056Swollman#include <sys/kernel.h> 552056Swollman#include <sys/ioctl.h> 562056Swollman#include <sys/uio.h> 573816Swollman#include <sys/devconf.h> 58637Snate 597430Sbde#include <machine/clock.h> 607430Sbde 612056Swollman#include <i386/isa/isa_device.h> 622056Swollman#include <i386/isa/icu.h> 63637Snate 64798Swollmanstatic int mseprobe(struct isa_device *); 65798Swollmanstatic int mseattach(struct isa_device *); 66798Swollmanvoid mseintr(int); 67637Snate 68637Snatestruct isa_driver msedriver = { 69637Snate mseprobe, mseattach, "mse" 70637Snate}; 71637Snate 72637Snate/* 73637Snate * Software control structure for mouse. The sc_enablemouse(), 74637Snate * sc_disablemouse() and sc_getmouse() routines must be called spl'd(). 75637Snate */ 76637Snate#define PROTOBYTES 5 77637Snatestruct mse_softc { 78637Snate int sc_flags; 79637Snate int sc_mousetype; 801549Srgrimes struct selinfo sc_selp; 81637Snate u_int sc_port; 82637Snate void (*sc_enablemouse)(); 83637Snate void (*sc_disablemouse)(); 84637Snate void (*sc_getmouse)(); 85637Snate int sc_deltax; 86637Snate int sc_deltay; 87637Snate int sc_obuttons; 88637Snate int sc_buttons; 89637Snate int sc_bytesread; 90637Snate u_char sc_bytes[PROTOBYTES]; 91637Snate} mse_sc[NMSE]; 92637Snate 93637Snate/* Flags */ 94637Snate#define MSESC_OPEN 0x1 95637Snate#define MSESC_WANT 0x2 96637Snate 97637Snate/* and Mouse Types */ 98637Snate#define MSE_LOGITECH 0x1 99637Snate#define MSE_ATIINPORT 0x2 1004259Sjkh#define MSE_LOGI_SIG 0xA5 101637Snate 102637Snate#define MSE_PORTA 0 103637Snate#define MSE_PORTB 1 104637Snate#define MSE_PORTC 2 105637Snate#define MSE_PORTD 3 106637Snate 107637Snate#define MSE_UNIT(dev) (minor(dev) >> 1) 108637Snate#define MSE_NBLOCKIO(dev) (minor(dev) & 0x1) 109637Snate 110637Snate/* 111637Snate * Logitech bus mouse definitions 112637Snate */ 113637Snate#define MSE_SETUP 0x91 /* What does this mean? */ 1144259Sjkh /* The definition for the control port */ 1154259Sjkh /* is as follows: */ 1168876Srgrimes 1174259Sjkh /* D7 = Mode set flag (1 = active) */ 1188876Srgrimes /* D6,D5 = Mode selection (port A) */ 1194259Sjkh /* 00 = Mode 0 = Basic I/O */ 1204259Sjkh /* 01 = Mode 1 = Strobed I/O */ 1214259Sjkh /* 10 = Mode 2 = Bi-dir bus */ 1224259Sjkh /* D4 = Port A direction (1 = input)*/ 1234259Sjkh /* D3 = Port C (upper 4 bits) */ 1244259Sjkh /* direction. (1 = input) */ 1254259Sjkh /* D2 = Mode selection (port B & C) */ 1264259Sjkh /* 0 = Mode 0 = Basic I/O */ 1274259Sjkh /* 1 = Mode 1 = Strobed I/O */ 1284259Sjkh /* D1 = Port B direction (1 = input)*/ 1294259Sjkh /* D0 = Port C (lower 4 bits) */ 1304259Sjkh /* direction. (1 = input) */ 1318876Srgrimes 1324259Sjkh /* So 91 means Basic I/O on all 3 ports,*/ 1334259Sjkh /* Port A is an input port, B is an */ 1344259Sjkh /* output port, C is split with upper */ 1354259Sjkh /* 4 bits being an output port and lower*/ 1364259Sjkh /* 4 bits an input port, and enable the */ 1374259Sjkh /* sucker. */ 1384259Sjkh /* Courtesy Intel 8255 databook. Lars */ 139637Snate#define MSE_HOLD 0x80 140637Snate#define MSE_RXLOW 0x00 141637Snate#define MSE_RXHIGH 0x20 142637Snate#define MSE_RYLOW 0x40 143637Snate#define MSE_RYHIGH 0x60 144637Snate#define MSE_DISINTR 0x10 145637Snate#define MSE_INTREN 0x00 146637Snate 147637Snatestatic int mse_probelogi(); 148637Snatestatic void mse_enablelogi(), mse_disablelogi(), mse_getlogi(); 149637Snate 150637Snate/* 151637Snate * ATI Inport mouse definitions 152637Snate */ 153637Snate#define MSE_INPORT_RESET 0x80 154637Snate#define MSE_INPORT_STATUS 0x00 155637Snate#define MSE_INPORT_DX 0x01 156637Snate#define MSE_INPORT_DY 0x02 157637Snate#define MSE_INPORT_MODE 0x07 158637Snate#define MSE_INPORT_HOLD 0x20 159637Snate#define MSE_INPORT_INTREN 0x09 160637Snate 161637Snatestatic int mse_probeati(); 162637Snatestatic void mse_enableati(), mse_disableati(), mse_getati(); 163637Snate 164637Snate#define MSEPRI (PZERO + 3) 165637Snate 166637Snate/* 167637Snate * Table of mouse types. 168637Snate * Keep the Logitech last, since I haven't figured out how to probe it 169637Snate * properly yet. (Someday I'll have the documentation.) 170637Snate */ 171637Snatestruct mse_types { 172637Snate int m_type; /* Type of bus mouse */ 173637Snate int (*m_probe)(); /* Probe routine to test for it */ 174637Snate void (*m_enable)(); /* Start routine */ 175637Snate void (*m_disable)(); /* Disable interrupts routine */ 176637Snate void (*m_get)(); /* and get mouse status */ 177637Snate} mse_types[] = { 178637Snate { MSE_ATIINPORT, mse_probeati, mse_enableati, mse_disableati, mse_getati }, 179637Snate { MSE_LOGITECH, mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi }, 180637Snate { 0, }, 181637Snate}; 182637Snate 1837780Swollmanstatic struct kern_devconf kdc_mse[NMSE] = { { 1847780Swollman 0, 0, 0, /* filled in by dev_attach */ 1857780Swollman "mse", 0, { MDDT_ISA, 0, "tty" }, 1867780Swollman isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, 1877780Swollman &kdc_isa0, /* parent */ 1887780Swollman 0, /* parentdata */ 1897780Swollman DC_UNCONFIGURED, /* state */ 1907780Swollman "ATI or Logitech bus mouse adapter", 1917780Swollman DC_CLS_MISC /* class */ 1927780Swollman} }; 1937780Swollman 1947780Swollmanstatic inline void 1957780Swollmanmse_registerdev(struct isa_device *id) 1967780Swollman{ 1977780Swollman if(id->id_unit) 1987780Swollman kdc_mse[id->id_unit] = kdc_mse[0]; 1997780Swollman kdc_mse[id->id_unit].kdc_unit = id->id_unit; 2007780Swollman kdc_mse[id->id_unit].kdc_isa = id; 2017780Swollman dev_attach(&kdc_mse[id->id_unit]); 2027780Swollman} 2037780Swollman 204798Swollmanint 205637Snatemseprobe(idp) 206637Snate register struct isa_device *idp; 207637Snate{ 208637Snate register struct mse_softc *sc = &mse_sc[idp->id_unit]; 209637Snate register int i; 210637Snate 2117780Swollman mse_registerdev(idp); 212637Snate /* 213637Snate * Check for each mouse type in the table. 214637Snate */ 215637Snate i = 0; 216637Snate while (mse_types[i].m_type) { 217637Snate if ((*mse_types[i].m_probe)(idp)) { 218637Snate sc->sc_mousetype = mse_types[i].m_type; 219637Snate sc->sc_enablemouse = mse_types[i].m_enable; 220637Snate sc->sc_disablemouse = mse_types[i].m_disable; 221637Snate sc->sc_getmouse = mse_types[i].m_get; 222637Snate return (1); 223637Snate } 224637Snate i++; 225637Snate } 226637Snate return (0); 227637Snate} 228637Snate 229798Swollmanint 230637Snatemseattach(idp) 231637Snate struct isa_device *idp; 232637Snate{ 233637Snate struct mse_softc *sc = &mse_sc[idp->id_unit]; 234637Snate 235637Snate sc->sc_port = idp->id_iobase; 2367780Swollman kdc_mse[idp->id_unit].kdc_state = DC_IDLE; 237637Snate return (1); 238637Snate} 239637Snate 240637Snate/* 241637Snate * Exclusive open the mouse, initialize it and enable interrupts. 242637Snate */ 243798Swollmanint 24410624Sbdemseopen(dev, flags, fmt, p) 245637Snate dev_t dev; 24610624Sbde int flags; 24710624Sbde int fmt; 24810624Sbde struct proc *p; 249637Snate{ 250637Snate register struct mse_softc *sc; 251637Snate int s; 252637Snate 253637Snate if (MSE_UNIT(dev) >= NMSE) 254637Snate return (ENXIO); 255637Snate sc = &mse_sc[MSE_UNIT(dev)]; 256637Snate if (sc->sc_flags & MSESC_OPEN) 257637Snate return (EBUSY); 258637Snate sc->sc_flags |= MSESC_OPEN; 2597780Swollman kdc_mse[MSE_UNIT(dev)].kdc_state = DC_BUSY; 260637Snate sc->sc_obuttons = sc->sc_buttons = 0x7; 261637Snate sc->sc_deltax = sc->sc_deltay = 0; 262637Snate sc->sc_bytesread = PROTOBYTES; 263637Snate 264637Snate /* 265637Snate * Initialize mouse interface and enable interrupts. 266637Snate */ 267637Snate s = spltty(); 268637Snate (*sc->sc_enablemouse)(sc->sc_port); 269637Snate splx(s); 270637Snate return (0); 271637Snate} 272637Snate 273637Snate/* 274637Snate * mseclose: just turn off mouse innterrupts. 275637Snate */ 276798Swollmanint 27710624Sbdemseclose(dev, flags, fmt, p) 278798Swollman dev_t dev; 27910624Sbde int flags; 28010624Sbde int fmt; 28110624Sbde struct proc *p; 282637Snate{ 283637Snate struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)]; 284637Snate int s; 285637Snate 286637Snate s = spltty(); 287637Snate (*sc->sc_disablemouse)(sc->sc_port); 288637Snate sc->sc_flags &= ~MSESC_OPEN; 2897780Swollman kdc_mse[MSE_UNIT(dev)].kdc_state = DC_IDLE; 290637Snate splx(s); 291637Snate return(0); 292637Snate} 293637Snate 2948876Srgrimes/* 295637Snate * mseread: return mouse info using the MSC serial protocol, but without 296637Snate * using bytes 4 and 5. 297637Snate * (Yes this is cheesy, but it makes the X386 server happy, so...) 298637Snate */ 299798Swollmanint 30010624Sbdemseread(dev, uio, ioflag) 301637Snate dev_t dev; 302637Snate struct uio *uio; 30310624Sbde int ioflag; 304637Snate{ 305637Snate register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)]; 306637Snate int xfer, s, error; 307637Snate 308637Snate /* 309637Snate * If there are no protocol bytes to be read, set up a new protocol 310637Snate * packet. 311637Snate */ 312637Snate s = spltty(); /* XXX Should be its own spl, but where is imlXX() */ 313637Snate if (sc->sc_bytesread >= PROTOBYTES) { 314637Snate while (sc->sc_deltax == 0 && sc->sc_deltay == 0 && 315637Snate (sc->sc_obuttons ^ sc->sc_buttons) == 0) { 316637Snate if (MSE_NBLOCKIO(dev)) { 317637Snate splx(s); 318637Snate return (0); 319637Snate } 320637Snate sc->sc_flags |= MSESC_WANT; 321637Snate if (error = tsleep((caddr_t)sc, MSEPRI | PCATCH, 322637Snate "mseread", 0)) { 323637Snate splx(s); 324637Snate return (error); 325637Snate } 326637Snate } 327637Snate 328637Snate /* 329637Snate * Generate protocol bytes. 330637Snate * For some reason X386 expects 5 bytes but never uses 331637Snate * the fourth or fifth? 332637Snate */ 333637Snate sc->sc_bytes[0] = 0x80 | (sc->sc_buttons & ~0xf8); 334637Snate if (sc->sc_deltax > 127) 335637Snate sc->sc_deltax = 127; 336637Snate if (sc->sc_deltax < -127) 337637Snate sc->sc_deltax = -127; 338637Snate sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */ 339637Snate if (sc->sc_deltay > 127) 340637Snate sc->sc_deltay = 127; 341637Snate if (sc->sc_deltay < -127) 342637Snate sc->sc_deltay = -127; 343637Snate sc->sc_bytes[1] = sc->sc_deltax; 344637Snate sc->sc_bytes[2] = sc->sc_deltay; 345637Snate sc->sc_bytes[3] = sc->sc_bytes[4] = 0; 346637Snate sc->sc_obuttons = sc->sc_buttons; 347637Snate sc->sc_deltax = sc->sc_deltay = 0; 348637Snate sc->sc_bytesread = 0; 349637Snate } 350637Snate splx(s); 3511567Srgrimes xfer = min(uio->uio_resid, PROTOBYTES - sc->sc_bytesread); 352637Snate if (error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio)) 353637Snate return (error); 354637Snate sc->sc_bytesread += xfer; 355637Snate return(0); 356637Snate} 357637Snate 358637Snate/* 359637Snate * mseselect: check for mouse input to be processed. 360637Snate */ 361798Swollmanint 362637Snatemseselect(dev, rw, p) 363637Snate dev_t dev; 364637Snate int rw; 365637Snate struct proc *p; 366637Snate{ 367637Snate register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)]; 368637Snate int s; 369637Snate 370637Snate s = spltty(); 371637Snate if (sc->sc_bytesread != PROTOBYTES || sc->sc_deltax != 0 || 372637Snate sc->sc_deltay != 0 || (sc->sc_obuttons ^ sc->sc_buttons) != 0) { 373637Snate splx(s); 374637Snate return (1); 375637Snate } 376637Snate 377637Snate /* 378637Snate * Since this is an exclusive open device, any previous proc. 379637Snate * pointer is trash now, so we can just assign it. 380637Snate */ 3811549Srgrimes selrecord(p, &sc->sc_selp); 382637Snate splx(s); 383637Snate return (0); 384637Snate} 385637Snate 386637Snate/* 387637Snate * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative. 388637Snate */ 389798Swollmanvoid 390637Snatemseintr(unit) 391637Snate int unit; 392637Snate{ 393637Snate register struct mse_softc *sc = &mse_sc[unit]; 394637Snate pid_t p; 395637Snate 396637Snate#ifdef DEBUG 397637Snate static int mse_intrcnt = 0; 398637Snate if((mse_intrcnt++ % 10000) == 0) 399637Snate printf("mseintr\n"); 400637Snate#endif /* DEBUG */ 401637Snate if ((sc->sc_flags & MSESC_OPEN) == 0) 402637Snate return; 403637Snate 404637Snate (*sc->sc_getmouse)(sc->sc_port, &sc->sc_deltax, &sc->sc_deltay, &sc->sc_buttons); 405637Snate 406637Snate /* 407637Snate * If mouse state has changed, wake up anyone wanting to know. 408637Snate */ 409637Snate if (sc->sc_deltax != 0 || sc->sc_deltay != 0 || 410637Snate (sc->sc_obuttons ^ sc->sc_buttons) != 0) { 4118876Srgrimes if (sc->sc_flags & MSESC_WANT) { 4128876Srgrimes sc->sc_flags &= ~MSESC_WANT; 4138876Srgrimes wakeup((caddr_t)sc); 4148876Srgrimes } 4151549Srgrimes selwakeup(&sc->sc_selp); 416637Snate } 417637Snate} 418637Snate 419637Snate/* 420637Snate * Routines for the Logitech mouse. 421637Snate */ 422637Snate/* 423637Snate * Test for a Logitech bus mouse and return 1 if it is. 424637Snate * (until I know how to use the signature port properly, just disable 425637Snate * interrupts and return 1) 426637Snate */ 427637Snatestatic int 428637Snatemse_probelogi(idp) 429637Snate register struct isa_device *idp; 430637Snate{ 431637Snate 4324259Sjkh int sig; 4334259Sjkh 4344259Sjkh outb(idp->id_iobase + MSE_PORTD, MSE_SETUP); 4354259Sjkh /* set the signature port */ 4364259Sjkh outb(idp->id_iobase + MSE_PORTB, MSE_LOGI_SIG); 4374259Sjkh 4384259Sjkh DELAY(30000); /* 30 ms delay */ 4394259Sjkh sig = inb(idp->id_iobase + MSE_PORTB) & 0xFF; 4404259Sjkh if (sig == MSE_LOGI_SIG) { 4414259Sjkh outb(idp->id_iobase + MSE_PORTC, MSE_DISINTR); 4424259Sjkh return(1); 4434259Sjkh } else { 4448876Srgrimes printf("mse%d: wrong signature %x\n",idp->id_unit,sig); 4454259Sjkh return(0); 446637Snate } 447637Snate} 448637Snate 449637Snate/* 450637Snate * Initialize Logitech mouse and enable interrupts. 451637Snate */ 452637Snatestatic void 453637Snatemse_enablelogi(port) 454637Snate register u_int port; 455637Snate{ 456637Snate int dx, dy, but; 457637Snate 458637Snate outb(port + MSE_PORTD, MSE_SETUP); 459637Snate mse_getlogi(port, &dx, &dy, &but); 460637Snate} 461637Snate 462637Snate/* 463637Snate * Disable interrupts for Logitech mouse. 464637Snate */ 465637Snatestatic void 466637Snatemse_disablelogi(port) 467637Snate register u_int port; 468637Snate{ 469637Snate 470637Snate outb(port + MSE_PORTC, MSE_DISINTR); 471637Snate} 472637Snate 473637Snate/* 474637Snate * Get the current dx, dy and button up/down state. 475637Snate */ 476637Snatestatic void 477637Snatemse_getlogi(port, dx, dy, but) 478637Snate register u_int port; 479637Snate int *dx; 480637Snate int *dy; 481637Snate int *but; 482637Snate{ 483637Snate register char x, y; 484637Snate 485637Snate outb(port + MSE_PORTC, MSE_HOLD | MSE_RXLOW); 486637Snate x = inb(port + MSE_PORTA); 487637Snate *but = (x >> 5) & 0x7; 488637Snate x &= 0xf; 489637Snate outb(port + MSE_PORTC, MSE_HOLD | MSE_RXHIGH); 490637Snate x |= (inb(port + MSE_PORTA) << 4); 491637Snate outb(port + MSE_PORTC, MSE_HOLD | MSE_RYLOW); 492637Snate y = (inb(port + MSE_PORTA) & 0xf); 493637Snate outb(port + MSE_PORTC, MSE_HOLD | MSE_RYHIGH); 494637Snate y |= (inb(port + MSE_PORTA) << 4); 495637Snate *dx += x; 496637Snate *dy += y; 497637Snate outb(port + MSE_PORTC, MSE_INTREN); 498637Snate} 499637Snate 500637Snate/* 501637Snate * Routines for the ATI Inport bus mouse. 502637Snate */ 503637Snate/* 504637Snate * Test for a ATI Inport bus mouse and return 1 if it is. 505637Snate * (do not enable interrupts) 506637Snate */ 507637Snatestatic int 508637Snatemse_probeati(idp) 509637Snate register struct isa_device *idp; 510637Snate{ 511637Snate int i; 512637Snate 513637Snate for (i = 0; i < 2; i++) 514637Snate if (inb(idp->id_iobase + MSE_PORTC) == 0xde) 515637Snate return (1); 516637Snate return (0); 517637Snate} 518637Snate 519637Snate/* 520637Snate * Initialize ATI Inport mouse and enable interrupts. 521637Snate */ 522637Snatestatic void 523637Snatemse_enableati(port) 524637Snate register u_int port; 525637Snate{ 526637Snate 527637Snate outb(port + MSE_PORTA, MSE_INPORT_RESET); 528637Snate outb(port + MSE_PORTA, MSE_INPORT_MODE); 529637Snate outb(port + MSE_PORTB, MSE_INPORT_INTREN); 530637Snate} 531637Snate 532637Snate/* 533637Snate * Disable interrupts for ATI Inport mouse. 534637Snate */ 535637Snatestatic void 536637Snatemse_disableati(port) 537637Snate register u_int port; 538637Snate{ 539637Snate 540637Snate outb(port + MSE_PORTA, MSE_INPORT_MODE); 541637Snate outb(port + MSE_PORTB, 0); 542637Snate} 543637Snate 544637Snate/* 545637Snate * Get current dx, dy and up/down button state. 546637Snate */ 547637Snatestatic void 548637Snatemse_getati(port, dx, dy, but) 549637Snate register u_int port; 550637Snate int *dx; 551637Snate int *dy; 552637Snate int *but; 553637Snate{ 554637Snate register char byte; 555637Snate 556637Snate outb(port + MSE_PORTA, MSE_INPORT_MODE); 557637Snate outb(port + MSE_PORTB, MSE_INPORT_HOLD); 558637Snate outb(port + MSE_PORTA, MSE_INPORT_STATUS); 559637Snate *but = ~(inb(port + MSE_PORTB) & 0x7); 560637Snate outb(port + MSE_PORTA, MSE_INPORT_DX); 561637Snate byte = inb(port + MSE_PORTB); 562637Snate *dx += byte; 563637Snate outb(port + MSE_PORTA, MSE_INPORT_DY); 564637Snate byte = inb(port + MSE_PORTB); 565637Snate *dy += byte; 566637Snate outb(port + MSE_PORTA, MSE_INPORT_MODE); 567637Snate outb(port + MSE_PORTB, MSE_INPORT_INTREN); 568637Snate} 569637Snate#endif /* NMSE */ 570