[alt.sources] Nintendo Joystick driver for UNIX/386

thinman@netcom.COM (Lance Norskog) (06/20/91)

Hello folks,

Well, there seems to an appreciable interest in my Nintendo (tm)
joystick driver for UNIX/386, so I'm posting it.

It's a Streams driver, and includes appropriate support files for
Thomas Roell's 386 UNIX X Window releases.

Enjoy!

Lance Norskog
thinman@netcom.com


#!/bin/sh
# This is a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 06/20/1991 01:56 UTC by thinman@netcom.com
# Source directory /usr/lance/vr/nes
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   4412 -rw-r--r-- README
#    577 -rw-r--r-- Makefile
#   9050 -rw-r--r-- nes.c
#   1546 -rw-r--r-- strobe.c
#  21649 -rw-r--r-- mouseX386.c
#    301 -rw-r--r-- nintendo.h
#     13 -rw-r--r-- Node
#     26 -rw-r--r-- System
#     67 -rw-r--r-- Master
#
# ============= README ==============
if test -f 'README' -a X"$1" != X"-c"; then
	echo 'x - skipping README (File already exists)'
else
echo 'x - extracting README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'README' &&
XHello-
X
XThis shar contains my Nintendo Entertainment System joystick driver.
XIt's a Streams driver for UNIX V.3/386.  It includes the support driver
Xfiles for the original release of Thomas Roell's 386/X11R4 software.
X
XThis has only been tested on an Orchid 386/20 motherboard running
XAT&T UNIX V.3.2.  You shouldn't have much trouble with normal 
Xvariants like ISC or Everex.  With terminally weird junk like SCO,
Xgood luck.  Edit the Master file to have the driver's major
Xdevice number in the indicated place.  Add Master as one line
Xin the file /etc/conf/cf.d/mdevice.  If you need to use a different
Xparallel port number, change the port in System and nes.c.
X
XThis project requires a little soldering, I'm afraid.  It was inspired
Xby an article in Byte magazine (July 1990, pp. 288-289) on attaching
Xa Mattel Power Glove to an IBM PC.  In fact, the article was not about
Xthe PG, but instead about attaching a Nintendo Joystick to a PC.
X
XIf you want to make the PG send raw data so you can do Virtual Reality 
Xwith it, this won't do it at all.  You need schematics which I can send 
Xyou, and real electronic skills, which I can't.
X
XThe driver includes constants for the parallel port # and the pins
Xattached.  The pinouts for the cable are:
X
XNintendo	Printer
X1	-	GND
X2	-	2  (Clock)
X3	-	3  (Reset)
X4	-	13 (Data)
X5	-	NC
X6	-	NC
X7	-	5V
X
XYou need to have a spare disk power connector in your PC.
XYou need to get the 5V and GND lines from this connector.
XI got empty shells for the big 4-pin Molexes and built a plug.
X
XDon't even think about doing this without an ohmmeter. 
X
XThe algorithm is simple: wiggle the Reset line, wait a bit.
XRead the status from the Data line.  This is the A button.
XFor 7 times wiggle the clock line, wait a bit, and read a bit.
XThis gives the other 3 buttons and the four direction buttons.
X
XThe strobe program demonstrates the use of the cable, and
Xallows you to test your cable without messing around with the kernel.
XYou will need to calibrate the waiting constant for your computer.
XYou will then need to transfer that constant to the variables
Xnes_c[1-5] in nes.c.  They seem to want to be the same.  The
Xconstant 20 came from a 20 mhz 386.  Mr. Joystick is fairly picky 
Xabout the range of times he's happy with, so you may have to mess
Xaround a bit with strobe.c.  When you're done, the program output 
Xshould reliably reflect the buttons.
X
XTo add it you Thomas Roell's X386 system, cd to server/ddx/at386 
Xin your X source tree.  The enclosed mouse.c dates from his original
X256-color release, Nov 8, 1990.  You may have to do something for
Xhis later versions.  The enclosed nintendo.h is included by mouse.c
X
XYou also need to add the following three lines to config.c:
X< #define NINTENDO 11
X<   { NINTENDO,  "nintendo" },
X< 	case NINTENDO:   X386LinkDevice(NesMouseConfig()); break;
XJust hunt for MICROSOFT, and you'll see where they go.
X
XNow, comment out the mouse config line in 
X/usr/lib/X11/X386/config/Xconfig and add this line:
X
X	Nintendo     "/dev/nes0" "A" "Select" "B" 10
X
XThis is to use /dev/nes0 (you might add more later, you never know)
Xand to configure NES "A" as the left button, NES "Select" as the
Xmiddle button, NES "B" as the right button, and an accelerator
Xvalue (see below) of 10.  The accelerator value is optional,
Xand defaults to 0, but you must give all three button descriptors!  
XThe button descriptors available are: "A", "B", "Select", "Start, 
Xand "AB".  The latter refers to simultaneously pressing A and B.  
XThe Power Glove does this in some modes; there is no timer-based 
Xheuristic for deciding that "A-50 milliseconds-B" counts as an AB.
X
XThe accelerator value makes the cursor speed up when you hold down
Xthe joystick button in one direction.  I find 3 to 5 pleasantly useable, 
Xand nicer than a mouse.  
X
XYou jaded Streams hackers may be in for a surprise.  Hint: search for
X"bucket" in nes.c.  Especially serial port Streams driver hackers.
X
XHomework: 1) add some dead time before starting acceleration.  2) add
Xtime smarts for the AB combination.  3) Bring up ZapGun (light pen)
Xsupport on a VGA card based on the Cirrus chip set, the only chipset
Xthat support light pens.  Pins 5 & 6 on the Nintendo plug are lightpen 
Xinput and trigger input.  It's handy for games, and you can get a 
Xhelmet with the ZapGun lightpen lens built in as a monocle.  Head
Xtracking doesn't have to cost $50,000.
X
XEnjoy!
X
XLance Norskog
Xthinman@netcom.com
SHAR_EOF
chmod 0644 README ||
echo 'restore of README failed'
Wc_c="`wc -c < 'README'`"
test 4412 -eq "$Wc_c" ||
	echo 'README: original size 4412, current size' "$Wc_c"
fi
# ============= Makefile ==============
if test -f 'Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping Makefile (File already exists)'
else
echo 'x - extracting Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
X#
X# Makefile for Nintendo joystick driver
X# 
X# Copyright 1991 Lance Norskog
X# 
X
XFILES= README Makefile nes.c strobe.c mouseX386.c nintendo.h Node System Master
X
Xall: nes.o strobe
X
Xstrobe: strobe.c
X	cc strobe.c -o strobe
X
Xinstall:
X	mkdir /etc/conf/pack.d/nes
X	rm -f /etc/conf/pack.d/nes/Driver.o 
X	cp nes.o /etc/conf/pack.d/nes/Driver.o
X	rm -f /etc/conf/sdevice.d/nes /etc/conf/node.d/nes
X	cp Node /etc/conf/node.d/nes
X	cp System /etc/conf/system.d/nes
X	echo "You did install the Master file, didn't you?"
X
Xshar: 
X	/usr2/tools/shar/shar -F -s thinman@netcom.com $(FILES)
X
XFRC: 
SHAR_EOF
chmod 0644 Makefile ||
echo 'restore of Makefile failed'
Wc_c="`wc -c < 'Makefile'`"
test 577 -eq "$Wc_c" ||
	echo 'Makefile: original size 577, current size' "$Wc_c"
fi
# ============= nes.c ==============
if test -f 'nes.c' -a X"$1" != X"-c"; then
	echo 'x - skipping nes.c (File already exists)'
else
echo 'x - extracting nes.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'nes.c' &&
X/*
X * NES streams driver.
X *
X * Derived, through several generations, from code typed in from 
X * the AT&T Streams Programmer's Guide.
X *
X * Supports Nintendeo Entertainment System joysticks via a parallel port.
X * No interrupts.  No zap-gun support.
X *
X * Each minor number corresponds to one joystick plug.  It should be possible
X * to hook up a few NES gizmos via parallel port.
X *
X * Copyright 1991, Lance C. Norskog
X *
X * version 0.1 - base, running with X
X * version 0.2 - switch to double-bucket input management
X */
X
X#include <sys/types.h>
X#include <sys/param.h>
X#include <sys/stream.h>
X#include <sys/stropts.h>
X#include <sys/sysmacros.h>
X#ifndef	__GNUC__
X#include <sys/inline.h>
X#endif
X#include <sys/errno.h>
X
Xstatic struct module_info rnes = {
X	3, "nes", 0, INFPSZ, 500, 100
X};
X
Xstatic struct module_info wnes = {
X	3, "nes", 0, INFPSZ, 500, 100
X};
X
Xstatic int nesopen(), nesclose(), neswput(), nesrsrv();
X
Xstatic struct qinit urqinit = {		/* Upper read */
X	0, nesrsrv, nesopen, nesclose, NULL, &rnes, 0
X};
X
Xstatic struct qinit uwqinit = {		/* Upper write */
X	neswput, 0, nesopen, nesclose, NULL, &wnes, 0
X};
X
Xstruct streamtab nesinfo = {
X	&urqinit, &uwqinit, NULL, NULL
X};
X
Xint nes_debug = 0, nes_notimer = 0, nes_nostrobe = 0;
X#define	debug(mask, x)	if (nes_debug & mask) printf x;
X/* 1 for upper-level, 2 for lower-level, 4 for input data */
X
Xint nes_in, 			/* number of input packets 		*/
X    nes_inb;			/* number of input bytes   		*/
Xint nes_nomblk, 		/* number of allocb failures		*/
X    nes_nodupb, 		/* number of dupb failures		*/
X    nes_full, 			/* number of buffer-full failures	*/
X    nes_cant, 			/* number of canput failures		*/
X    nes_busy;			/* number of bucket-busy		*/
X
Xint nes_bsize = 1024;		/* several seconds worth */
X
X#define	NNES	1
X
X#define	NES_right	0x01
X#define	NES_left	0x02
X#define	NES_down	0x04
X#define	NES_up		0x08
X#define	NES_start	0x10
X#define	NES_select	0x20
X#define	NES_B		0x40
X#define	NES_A		0x80
X
X#define	NES_SWITCHES	(NES_start | NES_select | NES_A | NES_B)
X#define	NES_MOVES	(NES_right | NES_left | NES_up | NES_up)
X
Xstruct	nes_nes {
X	unsigned short	ctrl_port, ctrl_clock, ctrl_reset,
X			data_port, data_mask,
X			ticks;
X	unsigned char	canopen;
X	queue_t	*rdq;
X	int	timer;
X	int	nes;			/* last buttons */
X	int	switches;
X	mblk_t	*mp, *other;		/* pointer to input blocks */
X} nes_nes[NNES] = {
X{
X	0x378,
X	1,
X	2,
X	0x379,
X	0x10,
X	HZ,
X}
X};
X
Xtypedef	struct nes_nes nes_t;
X
Xint nnes = NNES;
X
Xint nes_c1 = 20;
Xint nes_c2 = 20;
Xint nes_c3 = 20;
Xint nes_c4 = 20;
Xint nes_c5 = 20;
X
X/* move to space.c */
X
Xnesinit() {
X	int i, hz;
X
X	for(i=0; i<nnes; i++) {
X		nes_nes[i].rdq = (queue_t *) 0;
X		nes_nes[i].canopen = 1;
X		nes_strobe_init(&nes_nes[i]);
X		hz = HZ / nes_nes[i].ticks;
X		nes_nes[i].ticks = ((hz == 0) ? 1 : hz);
X		nes_nes[i].switches = 0;
X	}
X}
X
Xnesopen(q, dev, flag, sflag)
Xqueue_t *q;
X{
X	nes_t	*nes;
X	int	nes_timer();
X
X	if (sflag == CLONEOPEN) {
X		return OPENFAIL;
X/*		for (dev = 0; dev < nnes; dev++)
X			if (nes_nes[dev].rdq == (queue_t *) 0)
X				break; */
X	} else	dev = minor(dev);
X	if (dev > nnes)
X		return OPENFAIL;
X	nes = &nes_nes[dev];
X	if (nes->rdq)
X		return dev;
X
X	/* q_ptr is the q's repository for our per-chan structure */
X	q->q_ptr = (caddr_t) nes;
X	WR(q)->q_ptr = (caddr_t) nes;
X	nes->rdq = q;
X
Xdebug(1, ("Line %d\n", __LINE__));
X	/* Start timer */
X	if (! nes_notimer) 
X		nes->timer = timeout(nes_timer, q, nes->ticks);	
X	nes->mp = allocb(nes_bsize, BPRI_LO);
X	nes->other = allocb(nes_bsize, BPRI_LO);
X	if (! nes->mp)	nes_nomblk++;
X
Xdebug(1, ("Line %d\n", __LINE__));
X	return dev;
X}
X
Xstatic
Xnesclose(q)
Xqueue_t *q;
X{
X	nes_t *nes = (nes_t *) q->q_ptr;
X	mblk_t *mp;
X
Xdebug(1, ("Line %d\n", __LINE__));
X	untimeout(nes->timer);
X	nes->rdq = (queue_t *) 0;
X	if (nes->mp)
X		freemsg(nes->mp);
X	if (nes->other)
X		freemsg(nes->other);
X	nes->mp = (mblk_t *) 0;
X	nes->other = (mblk_t *) 0;
X	nes_strobe_init(nes);
Xdebug(1, ("Line %d\n", __LINE__));
X}
X
X/* This is called when, and only when, the above reader can read. */
X/*
X * Double-bucket method:
X *	Only send up when other bucket is finished processing.
X *	Always duplicate buffers before sending them up.
X */
Xnesrsrv(q)
Xqueue_t *q;
X{
X	nes_t *nes = (nes_t *) q->q_ptr;
X	mblk_t *mp;
X	int can, bytes = 0;
X
Xdebug(1, ("Line %d\n", __LINE__));
X	if (!nes->mp)
X		return;
X	if (nes->other && (nes->other->b_datap->db_ref > 1)) {
X		nes_busy++;
X		return;
X	}
Xdebug(1, ("Line %d\n", __LINE__));
X	if (! (bytes = (nes->mp->b_wptr > nes->mp->b_rptr)))
X		return;
X	can = canput(q->q_next);
Xdebug(1, ("Line %d\n", __LINE__));
X	if (! can) {
X		nes_cant++;
X		return;
X	}
X	if (!(mp = dupb(nes->mp))) {
X		nes_nodupb++;
X		return;
X	}
X
Xdebug(1, ("Line %d\n", __LINE__));
X	/* send up copy of current bucket */
X	nes_in++;
X	nes_inb += mp->b_wptr - mp->b_rptr;
X	putnext(q, mp);
X
X	/* Swap buckets */
X	mp = nes->other;
X	nes->other = nes->mp;
X	nes->mp = mp;
X
Xdebug(1, ("Line %d\n", __LINE__));
X	if (!nes->mp)
X		nes->mp = allocb(nes_bsize, BPRI_LO);
X	if (! nes->mp)	
X		nes_nomblk++;
X	else	/* reset read/write pointers of recycled bucket */
X		nes->mp->b_rptr = nes->mp->b_wptr = nes->mp->b_datap->db_base;
X}
X
X/* This is called strioctl(), whether or not it's there!  */
Xneswput(q, mp)
Xqueue_t *q;
Xmblk_t *mp;
X{
X	nes_t *nes = (nes_t *) q->q_ptr;
X
X	switch(mp->b_datap->db_type) {
X	    case M_IOCTL:
X		/* process */
X
X		mp->b_datap->db_type = M_IOCNAK;
X		qreply(q, mp);
X		break;
X	    
X	    /* flush handling must be here */
X	    case M_FLUSH:
X		if (*mp->b_rptr & FLUSHW)
X			flushq(q, FLUSHDATA);
X		if (*mp->b_rptr & FLUSHR) {
X			flushq(RD(q), FLUSHDATA);
X			*mp->b_rptr &= ~FLUSHW;
X			qreply(q, mp);
X		} else
X			freemsg(mp);
X		break;
X	    default:
X		freemsg(q, mp);
X	}
X}
X
Xnes_timer(q)
Xqueue_t *q;
X{
X	nes_t *nes = (nes_t *) q->q_ptr;
X	unsigned char bits, nes_strobe();
X	mblk_t *tmp;
X
X	if (nes_notimer)
X		goto resched;
Xdebug(2, ("Line %d\n", __LINE__));
X	if (!nes->mp && !(nes->mp = allocb(nes_bsize, BPRI_LO))) {
X		nes_nomblk++;
X		goto resched;
X	}
X
Xdebug(2, ("Line %d\n", __LINE__));
X	if (nes->mp->b_wptr == nes->mp->b_datap->db_lim) {
X		nes_full++;
X		goto resched;
X	}
X
Xdebug(2, ("Line %d\n", __LINE__));
X	bits = nes_strobe(nes);
X	if (((bits & NES_right) && (bits & NES_left)) ||
X	    ((bits & NES_up) && (bits & NES_down))) {
X		/* skip */
X	} else {
Xdebug(2, ("Line %d\n", __LINE__));
X		/* report on movement or change in switches */
X		if (bits || ((bits & (NES_SWITCHES)) != nes->switches)) {
X			*(nes->mp->b_wptr++) = bits;
Xdebug(2, ("Line %d\n", __LINE__));
X			qenable(nes->rdq);
X			nes->switches = (bits & NES_SWITCHES);
X		}
Xdebug(2, ("Line %d\n", __LINE__));
X	}
X   resched:
X	nes->timer = timeout(nes_timer, q, nes->ticks);
X}
X
X/* 
X * Put port in quiescent state
X */
X
Xnes_strobe_init(nes)
Xnes_t *nes;
X{
X	int i, j;
X
X	if (nes_nostrobe)
X		return;
X	for(i = 0; i < 8; i++)
X		if ((1<<i) & nes->data_mask)
X			break;
X	if (i == 8) {
X		nes->canopen = 0;
X		printf("NES%d: data_mask not set!\n", nes - nes_nes);
X	}
X	outb(nes->ctrl_port, 0);
X	outb(nes->data_port, 0);
X}
X
X#define	hold(clk)		for(slow = clk; slow; slow--);
X
X/* Actually strobe the NES and add events to the record */
Xunsigned char
Xnes_strobe(nes)
Xnes_t *nes;
X{
X	int i, slow;
X	unsigned char data;
X	unsigned short bits = 0;	/* not char! */
X
Xdebug(2, ("Line %d\n", __LINE__));
X	if (nes_nostrobe)
X		return 0;
X/*
X#ifndef	__GNUC__
X	intr_disable();
X#endif
X*/
Xdebug(2, ("Line %d\n", __LINE__));
X	outb(nes->ctrl_port, nes->ctrl_reset | nes->ctrl_clock);
X	hold(nes_c1);
X	outb(nes->ctrl_port, nes->ctrl_clock);
X	hold(nes_c2);
X	for(i = 0; i < 8; i++) {
X		data = inb(nes->data_port);
X		bits |= (data & nes->data_mask);
X		hold(nes_c3);
X		outb(nes->ctrl_port, 0);
X		hold(nes_c4);
X		outb(nes->ctrl_port, nes->ctrl_clock);
X		hold(nes_c5);
X		bits <<= 1;
X	}
Xdebug(2, ("Line %d\n", __LINE__));
X	/* bits now straddles word, is upwards by one */
X	/* downshift into place */
X	for(i = 0; i < 8; i++) {
X		bits >>= 1; 
X		if (nes->data_mask & (1 << i))
X			break;
X	}
Xdebug(2, ("Line %d\n", __LINE__));
X/*
X#ifndef	__GNUC__
X	intr_restore();
X#endif
X*/
Xdebug(2, ("Line %d\n", __LINE__));
X	bits = ~bits;
Xif (bits && (nes_debug & 4))
X		printf("Input: 0x%x\n", bits & 0x1ff);
X	return (unsigned char) bits;
X}
X
Xstatic char *
XM_string(type)
X{
X	switch(type) {
X		case M_DATA:	return "M_DATA";
X		case M_PROTO:	return "M_PROTO";
X		case M_BREAK:	return "M_BREAK";
X		case M_PASSFP:	return "M_PASSFP";
X		case M_SIG:	return "M_SIG";
X		case M_DELAY:	return "M_DELAY";
X		case M_CTL:	return "M_CTL";
X		case M_IOCTL:	return "M_IOCTL";
X		case M_SETOPTS:	return "M_SETOPTS";
X		case M_IOCACK:	return "M_IOCACK";
X		case M_IOCNAK:	return "M_IOCNAK";
X		case M_PCPROTO:	return "M_PCPROTO";
X		case M_PCSIG:	return "M_PCSIG";
X		case M_FLUSH:	return "M_FLUSH";
X		case M_STOP:	return "M_STOP";
X		case M_START:	return "M_START";
X		case M_HANGUP:	return "M_HANGUP";
X		case M_ERROR:	return "M_ERROR";
X		default:	return "M_UNKNOWN";
X	}
X}
X
Xnesintr() {;}
X/* Don't digest it here.
X		if (bits & NES_right)
X			nes->right++;
X		if (bits & NES_left)
X			nes->left++;
X		if (bits & NES_up)
X			nes->up++;
X		if (bits & NES_down)
X			nes->down++;
X
X		if (bits & NES_A)
X			nes->A = 1;
X		if (bits & NES_B)
X			nes->B = 1;
X*/
X
SHAR_EOF
chmod 0644 nes.c ||
echo 'restore of nes.c failed'
Wc_c="`wc -c < 'nes.c'`"
test 9050 -eq "$Wc_c" ||
	echo 'nes.c: original size 9050, current size' "$Wc_c"
fi
# ============= strobe.c ==============
if test -f 'strobe.c' -a X"$1" != X"-c"; then
	echo 'x - skipping strobe.c (File already exists)'
else
echo 'x - extracting strobe.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'strobe.c' &&
X/*
X * Subroutine and test program to strobe NES controller.
X * Jan 5, 1990
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/param.h>
X#include <sys/at_ansi.h>
X#include <sys/inline.h>
X#include <sys/kd.h>
X
Xunsigned char strobe( /* unsigned char port */ );
X
Xmain() {
X	unsigned char old, new;
X	extern errno;
X
X	old = new = 0;
X	setbuf(stdout, (char *) 0);
X	errno = 0;
X	ioctl(0, KDADDIO, 0x378);
X	if (errno) {
X		perror("ADDIO");
X	}
X	ioctl(0, KDADDIO, 0x379);
X	if (errno) {
X		perror("ADDIO");
X	}
X	ioctl(0, KDADDIO, 0x37a);
X	if (errno) {
X		perror("ADDIO");
X	}
X	ioctl(0, KDENABIO);
X	if (errno) {
X		perror("ENABIO");
X	}
X	strobe_init(0x378);
X	while(1) {
X		new = strobe(0x378);
X		if (new != old) 
X			printf("%02x  ", new);
X		old = new;
X	}
X}
X
X#define	NES_CLOCK	0x1		/* to port */
X#define	NES_RESET	0x2		/* to port */
X#define	NES_DATA	0x10		/* from port + 1 */
X
Xunsigned char nes_shift[16] = { 4, 5, 6, 7, 8, 9, 10, 11 };
X
Xint c1 = 20;
Xint c2 = 20;
Xint c3 = 20;
Xint c4 = 20;
Xint c5 = 20;
X
Xstrobe_init(port)
X{
X	outb(port, 0);
X	outb(port+1, 0);
X}
X
X#define	hold(clk)		for(slow = clk; slow; slow--);
X
Xunsigned char
Xstrobe(port)
Xint port;
X{
X	int i, slow;
X	unsigned char data;
X	unsigned short bits = 0;
X	unsigned char xx[8];
X
X	/* stop interrupts */
X	outb(port, NES_RESET | NES_CLOCK);
X	hold(c1);
X	outb(port, NES_CLOCK);
X	hold(c2);
X	for(i = 0; i < 8; i++) {
X		data = inb(port + 1);
X		bits |= ((data & NES_DATA) << nes_shift[i]);
X		hold(c5);
X		outb(port, 0);
X		hold(c3);
X		outb(port, NES_CLOCK);
X		hold(c4);
X	}
X	bits >>= 8; 
X	return (unsigned char) ~bits;
X}
SHAR_EOF
chmod 0644 strobe.c ||
echo 'restore of strobe.c failed'
Wc_c="`wc -c < 'strobe.c'`"
test 1546 -eq "$Wc_c" ||
	echo 'strobe.c: original size 1546, current size' "$Wc_c"
fi
# ============= mouseX386.c ==============
if test -f 'mouseX386.c' -a X"$1" != X"-c"; then
	echo 'x - skipping mouseX386.c (File already exists)'
else
echo 'x - extracting mouseX386.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mouseX386.c' &&
X/*
X * Copyright 1990 by Thomas Roell, Dinkelscherben, Germany.
X *
X * Permission to use, copy, modify, distribute, and sell this software and its
X * documentation for any purpose is hereby granted without fee, provided that
X * the above copyright notice appear in all copies and that both that
X * copyright notice and this permission notice appear in supporting
X * documentation, and that the name of Thomas Roell not be used in
X * advertising or publicity pertaining to distribution of the software without
X * specific, written prior permission.  Thomas Roell makes no representations
X * about the suitability of this software for any purpose.  It is provided
X * "as is" without express or implied warranty.
X *
X * THOMAS ROELL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
X * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
X * EVENT SHALL THOMAS ROELL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
X * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
X * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
X * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
X * PERFORMANCE OF THIS SOFTWARE.
X *
X * Author:  Thomas Roell, roell@lan.informatik.tu-muenchen.de
X *
X * $Header: /proj/X11/mit/server/ddx/at386/RCS/mouse.c,v 1.6 90/11/08 17:49:14 root Exp $
X */
X
X
X#include "X386.h"
X#include "inputstr.h"
X#include "scrnintstr.h"
X#include "nintendo.h"
X
X/*
X * Private structure for a MouseSystems Mouse
X */
Xtypedef struct {
X  X386MouseRec  info;
X  int           state;
X  int           buttons;
X  int           dx,dy;
X} MouseSysRec, * MouseSysPtr;
X 
X/*
X * Private structure for a Microsoft Mouse
X */
Xtypedef struct {
X  X386MouseRec  info;
X  int           state;
X  int           emulate;
X  int           buttons;
X  int           dx,dy;
X} MicrosoftRec, *MicrosoftPtr;
X 
X/*
X * Private structure for a Bus Mouse
X */
Xtypedef struct {
X  X386MouseRec  info;
X  int           state;
X  int           buttons;
X  int           dx,dy;
X} BusMouseRec, *BusMousePtr;
X
X/*
X * Private structure for a Nintendo Joystick fake mouse
X * Supports configured mappings NES switches to mouse buttons,
X * and non-linear sped up joystick inputs.
X */
Xtypedef struct {
X  X386MouseRec  info;
X  int		switches;		    /* last NES switches */
X  int		moves;			    /* last NES move bits */
X  int           buttons;		    /* X buttons */
X  int           dx,dy;			    /* accumulated movement */
X  int		add, dda, shift;	    /* nonlinear motion inputs */
X  int		A, B, Start, Select, AB;    /* what makes left-middle-right ? */
X} NesMouseRec, *NesMousePtr;
X
X/*
X * lets create a simple finite-state machine
X */
X
Xstatic char state[24][3] = {
X  {-1,-1,0},  {-1,-1,4},  {-1,-1,8},  {2, -1,12}, /* nothing pressed */
X  { 1, 0,0},  { 1,-1,16}, { 1, 0,8},  {2, -1,12}, /* delayed right */
X  { 4, 0,0},  { 4, 0,4},  { 4,-1,20}, {2, -1,12}, /* delayed left */
X  { 0,-1,0},  { 0,-1,0},  { 0,-1,0},  {-1,-1,12}, /* pressed middle */
X  { 0,-1,0},  {-1,-1,16}, { 0,-1,8},  { 0, 2,12}, /* pressed right */
X  { 0,-1,0},  { 0,-1,4},  {-1,-1,20}, { 0, 2,12}, /* pressed left */
X};
X
X  
X/*
X *-----------------------------------------------------------------------
X * MouseCtrl --
X *      Alter the control parameters for the mouse.
X *
X * Results:
X *      None.
X *
X * Side Effects:
X *      None.
X *
X *-----------------------------------------------------------------------
X */
Xstatic void
XMouseCtrl(pMouse, pCtrl)
X     DevicePtr pMouse;
X     PtrCtrl   *pCtrl;
X{
X  X386MousePtr pPriv = (X386MousePtr)pMouse->devicePrivate;
X
X  TRACE( ("MouseCtrl(pMouse=0x%x, pCtrl=0x%x)\n", pMouse, pCtrl) );
X
X  /*
X   * check for reasonable values 
X   */
X  if ((pCtrl->num > 0) && (pCtrl->den > 0)) {
X    pPriv->num = pCtrl->num;
X    pPriv->den = pCtrl->den;
X  } else {
X    pPriv->num = 1;
X    pPriv->den = 1;
X  }
X
X  if (pCtrl->threshold > 0)
X    pPriv->threshold = pCtrl->threshold;
X  else
X    pPriv->threshold = 1;
X}
X
X/*
X *-----------------------------------------------------------------------
X * GetMotionEvents --
X *      Return the (number of) motion events in the "motion history
X *      buffer" (snicker) between the given times.
X *
X * Results:
X *      The number of events stuffed.
X *
X * Side Effects:
X *      None.
X *
X *-----------------------------------------------------------------------
X */
Xstatic int
XGetMotionEvents (buff, start, stop, pScreen)
X     CARD32 start, stop;
X     xTimecoord *buff;
X     ScreenPtr pScreen;
X{
X  TRACE( ("GetMotionEvents(buff=0x%x, start=%d, stop=%d, pScreen=0x%x)\n",
X	  buff, start, stop, pScreen) );
X
X  return 0;
X}
X
X/*
X *-----------------------------------------------------------------------
X * MouseSysProc --
X *      Handle the initialization, etc. of a mouse
X *
X * Results:
X *      none.
X *
X * Side Effects:
X *      none.
X *
X *-----------------------------------------------------------------------
X */
Xstatic int
XMouseSysProc(pMouse, what)
X     DevicePtr	pMouse;
X     int        what;
X{
X  unchar        map[4];
X  struct        termio tty;
X  Atom          type;
X  X386DevicePtr pPriv = (X386DevicePtr)pMouse->devicePrivate;
X  
X  TRACE( ("MouseSysProc(pMouse=0x%x, what=%d)\n", pMouse, what) );
X
X  switch (what)
X    {
X    case DEVICE_INIT: 
X      if ((pPriv->Fd = open(pPriv->Name,O_RDONLY | O_NDELAY)) < 0) {
X	ErrorF ("Cannot open MouseSystemsMouse\n");
X	return (!Success); }
X      ioctl(pPriv->Fd,TCGETA,&tty);  
X      tty.c_iflag = IGNBRK | IGNPAR ;     
X      tty.c_oflag = 0;           
X      tty.c_cflag = B1200 | CS8 | CSTOPB | CREAD | CLOCAL;
X      tty.c_lflag = 0;
X      tty.c_cc[VTIME]=0; 
X      tty.c_cc[VMIN]=1;
X      ioctl(pPriv->Fd,TCSETA,&tty);
X
X      ((MouseSysPtr)pPriv)->state = 0;
X      ((X386MousePtr)pPriv)->buttons = 0;
X      ((X386MousePtr)pPriv)->x = 0;
X      ((X386MousePtr)pPriv)->y = 0;
X      pMouse->on = FALSE;
X
X      map[1] = 3;
X      map[2] = 2;
X      map[3] = 1;
X      InitPointerDeviceStruct(pMouse, map, 3, GetMotionEvents, MouseCtrl, 0);
X
X#ifdef XINPUT
X      type = MakeAtom(pPriv->type, strlen(pPriv->type), FALSE);
X      AssignTypeAndName(pMouse, type, "Mouse Systems Mouse");
X#endif      
X
X      break;
X	
X      case DEVICE_ON:
X	AddEnabledDevice(pPriv->Fd); 
X	pMouse->on = TRUE;
X	break;
X	
X      case DEVICE_CLOSE:
X      case DEVICE_OFF:
X	RemoveEnabledDevice(pPriv->Fd); 
X	pMouse->on = FALSE;
X	break;
X    }
X  return Success;
X}
X
X/*
X *-----------------------------------------------------------------------
X * MouseSysProcessEvents --
X *      Return the number of processed events.
X *
X * Results:
X *      Number of events processed.
X *
X * Side Effects:
X *      Process Events.
X *-----------------------------------------------------------------------
X */
Xstatic void
XMouseSysProcessEvents(pMouse)
X     DevicePtr    pMouse;
X{
X  unchar          rBuf[64];
X  int             i,nBytes;
X  MouseSysPtr pPriv = (MouseSysPtr)pMouse->devicePrivate;
X
X  nBytes = read(((X386DevicePtr)pPriv)->Fd, rBuf, sizeof(rBuf));
X
X  for ( i=0; i < nBytes; i++) {
X    switch(pPriv->state) {
X    case 0:
X      if ((rBuf[i] & 0xF8) == 0x80) {
X	pPriv->buttons = (~rBuf[i]) & 0x07;
X	(pPriv->state)++; }
X      break;
X      
X    case 1:
X      pPriv->dx = (signed char)rBuf[i];
X      (pPriv->state)++;
X      break;
X      
X    case 2:
X      pPriv->dy = (signed char)rBuf[i];
X      (pPriv->state)++;
X      break;
X      
X    case 3:
X      (pPriv->dx) += (signed char)rBuf[i];
X      (pPriv->state)++;
X      break;
X      
X    case 4:
X      (pPriv->dy) += (signed char)rBuf[i];
X      pPriv->state = 0;
X      X386MouseEvent(pMouse, pPriv->buttons, pPriv->dx, -pPriv->dy);
X      break;
X    }
X  }
X}
X
X
X/*
X *-----------------------------------------------------------------------
X * MouseSysConfig --
X *	Read the configuration of a MouseSystems Mouse.
X *
X * Results:
X *	A pointer to the allocated device.
X *
X * Side Effects:
X *
X *-----------------------------------------------------------------------
X */
XX386DevicePtr
XMouseSysConfig()
X{
X  X386DevicePtr dev;
X
X  TRACE( ("MouseSysConfig()\n") );
X
X  if (X386Lex(NULL) != STRING)
X    FatalError("Devicename expected (%d)\n",X386LineNo);
X
X  dev = (X386DevicePtr)xalloc(sizeof(MouseSysRec));
X  dev->deviceProc   = MouseSysProc;
X  dev->deviceEvents = MouseSysProcessEvents;
X  dev->type = "MOUSE";
X  dev->Name = X386Val.str;
X  return dev;
X}
X
X/*
X *-----------------------------------------------------------------------
X * MicrosoftProc --
X *      Handle the initialization, etc. of a mouse
X *
X * Results:
X *      none.
X *
X * Side Effects:
X *      none.
X *
X *-----------------------------------------------------------------------
X */
Xstatic int
XMicrosoftProc(pMouse, what)
X     DevicePtr	pMouse;
X     int        what;
X{
X  unchar        map[4];
X  struct        termio tty;
X  Atom          type;
X  X386DevicePtr pPriv = (X386DevicePtr)pMouse->devicePrivate;
X
X  TRACE( ("MicrosoftProc(pMouse=0x%x, what=%d)\n", pMouse, what) );
X  
X  switch (what)
X    {
X    case DEVICE_INIT: 
X      if ((pPriv->Fd= open(pPriv->Name,O_RDONLY | O_NDELAY)) < 0) {
X	Error ("Cannot open MicrosoftMouse\n");
X	return (!Success); }
X      ioctl(pPriv->Fd,TCGETA,&tty);  
X      tty.c_iflag = IGNBRK | IGNPAR ;     
X      tty.c_oflag = 0;           
X      tty.c_cflag = B1200 | CS7 | CREAD | CLOCAL;
X      tty.c_lflag = 0;
X      tty.c_cc[VTIME]=0; 
X      tty.c_cc[VMIN]=1;
X      ioctl(pPriv->Fd,TCSETA,&tty);
X      
X      ((MicrosoftPtr)pPriv)->state = 0;
X      ((MicrosoftPtr)pPriv)->emulate = 0;
X      ((X386MousePtr)pPriv)->buttons = 0;
X      ((X386MousePtr)pPriv)->x = 0;
X      ((X386MousePtr)pPriv)->y = 0;
X      pMouse->on = FALSE;
X 
X      map[1] = 3;
X      map[2] = 2;
X      map[3] = 1;
X      InitPointerDeviceStruct(pMouse, map, 3, GetMotionEvents, MouseCtrl, 0);
X
X#ifdef XINPUT
X      type = MakeAtom(pPriv->type, strlen(pPriv->type), FALSE);
X      AssignTypeAndName(pMouse, type, "Microsoft Mouse");
X#endif
X
X      break;
X      
X    case DEVICE_ON:
X      AddEnabledDevice(pPriv->Fd);
X      pMouse->on = TRUE;
X      break;
X      
X    case DEVICE_CLOSE:
X    case DEVICE_OFF:
X      RemoveEnabledDevice(pPriv->Fd);
X      pMouse->on = FALSE;
X      break;
X      
X    }
X  return Success;
X}
X
X/*
X *-----------------------------------------------------------------------
X * MicrosoftProcessEvents --
X *      Return the number of processed events.
X *
X * Results:
X *      Number of events processed.
X *
X * Side Effects:
X *      Process Events.
X *-----------------------------------------------------------------------
X */
Xstatic void
XMicrosoftProcessEvents(pMouse)
X     DevicePtr    pMouse;
X{
X  unchar           rBuf[64];
X  int              i,nBytes;
X  MicrosoftPtr pPriv = (MicrosoftPtr)pMouse->devicePrivate;
X
X  nBytes = read(((X386DevicePtr)pPriv)->Fd, rBuf, sizeof(rBuf));
X
X  for ( i=0; i < nBytes; i++) {
X    switch(pPriv->state) {
X    case 0:
X      if ((rBuf[i] & 0x40) == 0x40) {
X	pPriv->buttons= (rBuf[i]>>4) &0x3;
X	pPriv->dy = (signed char)((rBuf[i] &0xC) <<4);
X	pPriv->dx = (signed char)((rBuf[i] &0x3) <<6);
X	(pPriv->state)++; }
X      break;
X      
X    case 1:
X      (pPriv->dx) |= (signed char)(rBuf[i]&0x3F);
X      (pPriv->state)++;
X      break;
X      
X    case 2:
X      (pPriv->dy) |= (signed char)(rBuf[i]&0x3F);
X      pPriv->state = 0;
X      X386MouseEvent(pMouse, 
X		 ((X386MousePtr)pPriv)->buttons, pPriv->dx, pPriv->dy);
X      /*
X       * emulate the third button by the other two
X       */
X      if (state[pPriv->buttons + pPriv->emulate][0] != -1)
X	X386MouseEvent(pMouse, state[pPriv->buttons+pPriv->emulate][0], 0, 0);
X      if (state[pPriv->buttons + pPriv->emulate][1] != -1)
X	X386MouseEvent(pMouse, state[pPriv->buttons+pPriv->emulate][1], 0, 0);
X
X      pPriv->emulate = state[pPriv->buttons + pPriv->emulate][2];
X      break;
X    }
X  }
X}
X
X
X/*
X *-----------------------------------------------------------------------
X * MicrosoftConfig --
X *	Read the configuration of a MicroTrash (tm) Mouse.
X *
X * Results:
X *	A pointer to the allocated device.
X *
X * Side Effects:
X *
X *-----------------------------------------------------------------------
X */
XX386DevicePtr
XMicrosoftConfig()
X{
X  X386DevicePtr dev;
X
X  TRACE( ("MircosoftConfig()\n") );
X
X  if (X386Lex(NULL) != STRING)
X    FatalError("Devicename expected (%d)\n",X386LineNo);
X
X  dev = (X386DevicePtr)xalloc(sizeof(MicrosoftRec));
X  dev->deviceProc   = MicrosoftProc;
X  dev->deviceEvents = MicrosoftProcessEvents;
X  dev->type = "MOUSE";
X  dev->Name = X386Val.str;
X  return dev;
X}
X
X
X/*
X *-----------------------------------------------------------------------
X * BusMouseProc --
X *      Handle the initialization, etc. of a mouse
X *
X * Results:
X *      none.
X *
X * Side Effects:
X *      none.
X *
X *-----------------------------------------------------------------------
X */
Xstatic int
XBusMouseProc(pMouse, what)
X     DevicePtr	pMouse;
X     int        what;
X{
X  unchar        map[4];
X  Atom          type;
X  X386DevicePtr pPriv = (X386DevicePtr)pMouse->devicePrivate;
X
X  TRACE( ("BusMouseProc(pMouse=0x%x, what=%d)\n", pMouse, what) );
X  
X  switch (what)
X    {
X    case DEVICE_INIT: 
X      if ((pPriv->Fd= open(pPriv->Name,O_RDONLY | O_NDELAY)) < 0) {
X	Error ("Cannot open BusMouse\n");
X	return (!Success); }
X      
X      ((BusMousePtr)pPriv)->state = 0;
X      ((X386MousePtr)pPriv)->buttons = 0;
X      ((X386MousePtr)pPriv)->x = 0;
X      ((X386MousePtr)pPriv)->y = 0;
X      pMouse->on = FALSE;
X 
X      map[1] = 3;
X      map[2] = 2;
X      map[3] = 1;
X      InitPointerDeviceStruct(pMouse, map, 3, GetMotionEvents, MouseCtrl, 0);
X
X#ifdef XINPUT
X      type = MakeAtom(pPriv->type, strlen(pPriv->type), FALSE);
X      AssignTypeAndName(pMouse, type, "Bus Mouse");
X#endif
X
X      break;
X      
X    case DEVICE_ON:
X      AddEnabledDevice(pPriv->Fd);
X      pMouse->on = TRUE;
X      break;
X      
X    case DEVICE_CLOSE:
X    case DEVICE_OFF:
X      RemoveEnabledDevice(pPriv->Fd);
X      pMouse->on = FALSE;
X      break;
X      
X    }
X  return Success;
X}
X
X/*
X *-----------------------------------------------------------------------
X * BusMouseProcessEvents --
X *      Process the good old BusMouse events.
X *
X * Results:
X *      Number of events processed.
X *
X * Side Effects:
X *      Process Events.
X *-----------------------------------------------------------------------
X */
Xstatic void
XBusMouseProcessEvents(pMouse)
X     DevicePtr    pMouse;
X{
X  unchar           rBuf[64];
X  int              i,nBytes;
X  BusMousePtr  pPriv = (BusMousePtr)pMouse->devicePrivate;
X
X  nBytes = read(((X386DevicePtr)pPriv)->Fd, rBuf, sizeof(rBuf));
X
X  for ( i=0; i < nBytes; i++) {
X    switch(pPriv->state) {
X    case 0:
X      if ((rBuf[i] & 0xF8) == 0x80) {
X	pPriv->buttons= (~rBuf[i]) &0x7;
X	(pPriv->state)++; }
X      break;
X      
X    case 1:
X      (pPriv->dx) = (signed char)(rBuf[i]);
X      (pPriv->state)++;
X      break;
X      
X    case 2:
X      (pPriv->dy) = (signed char)(rBuf[i]);
X      (pPriv->state)++;
X      break;
X
X    case 3:
X      (pPriv->state)++;
X      break;
X
X    case 4:
X      pPriv->state = 0;
X      X386MouseEvent(pMouse, pPriv->buttons, pPriv->dx, -pPriv->dy);
X      break;
X    }
X  }
X}
X
X
X/*
X *-----------------------------------------------------------------------
X * BusMouseConfig --
X *	Read the configuration of a BusMouse.
X *
X * Results:
X *	A pointer to the allocated device.
X *
X * Side Effects:
X *
X *-----------------------------------------------------------------------
X */
XX386DevicePtr
XBusMouseConfig()
X{
X  X386DevicePtr dev;
X
X  TRACE( ("BusMouseConfig()\n") );
X
X  if (X386Lex(NULL) != STRING)
X    FatalError("Devicename expected (%d)\n",X386LineNo);
X
X  dev = (X386DevicePtr)xalloc(sizeof(BusMouseRec));
X  dev->deviceProc   = BusMouseProc;
X  dev->deviceEvents = BusMouseProcessEvents;
X  dev->type = "MOUSE";
X  dev->Name = X386Val.str;
X  return dev;
X}
X
X/*
X *-----------------------------------------------------------------------
X * NesMouseProc --
X *      Handle the initialization, etc. of a Nintendo fake mouse
X *
X * Results:
X *      none.
X *
X * Side Effects:
X *      none.
X *
X *-----------------------------------------------------------------------
X */
Xstatic int
XNesMouseProc(pMouse, what)
X     DevicePtr	pMouse;
X     int        what;
X{
X  unchar        map[4];
X  Atom          type;
X  X386DevicePtr pPriv = (X386DevicePtr)pMouse->devicePrivate;
X
X  TRACE( ("NesMouseProc(pMouse=0x%x, what=%d)\n", pMouse, what) );
X  
X  switch (what)
X    {
X    case DEVICE_INIT: 
X      if ((pPriv->Fd= open(pPriv->Name,O_RDONLY | O_NDELAY)) < 0) {
X	Error ("Cannot open NesMouse\n");
X	return (!Success); }
X      
X      ((NesMousePtr)pPriv)->switches = 0;
X      ((NesMousePtr)pPriv)->moves = 0;
X      /* dda is set earlier, in NesMouseConfig */
X      ((NesMousePtr)pPriv)->add = 128;
X      ((NesMousePtr)pPriv)->shift = 7;
X      ((X386MousePtr)pPriv)->buttons = 0;
X      ((X386MousePtr)pPriv)->x = 0;
X      ((X386MousePtr)pPriv)->y = 0;
X      pMouse->on = FALSE;
X 
X      map[1] = 3;
X      map[2] = 2;
X      map[3] = 1;
X      InitPointerDeviceStruct(pMouse, map, 3, GetMotionEvents, MouseCtrl, 0);
X
X#ifdef XINPUT
X      type = MakeAtom(pPriv->type, strlen(pPriv->type), FALSE);
X      AssignTypeAndName(pMouse, type, "NES Mouse");
X#endif
X
X      break;
X      
X    case DEVICE_ON:
X      AddEnabledDevice(pPriv->Fd);
X      pMouse->on = TRUE;
X      break;
X      
X    case DEVICE_CLOSE:
X    case DEVICE_OFF:
X      RemoveEnabledDevice(pPriv->Fd);
X      pMouse->on = FALSE;
X      break;
X      
X    }
X  return Success;
X}
X
X/*
X *-----------------------------------------------------------------------
X * NesMouseProcessEvents --
X *      Process the good old NesMouse events.
X *
X * Results:
X *      Number of events processed.
X *
X * Side Effects:
X *      Process Events.
X *-----------------------------------------------------------------------
X */
Xstatic void
XNesMouseProcessEvents(pMouse)
X     DevicePtr    pMouse;
X{
X  unchar           rBuf[1024];	/* we can get lots of NES bytes */
X  int              i,nBytes;
X  NesMousePtr  pPriv = (NesMousePtr)pMouse->devicePrivate;
X  int		   doinput;
X
X  nBytes = read(((X386DevicePtr)pPriv)->Fd, rBuf, sizeof(rBuf));
X
X  /* Each byte is encoded as per nintendo.h.  Many samples a second. */
X  /* 
X   * Decode motion linearly.  With 1K read channel, we can be assured 
X   * of pulling all current input.  
X   */
X  pPriv->dx = pPriv->dy = 0;
X  doinput = 0;
X  for ( i=0; i < nBytes; i++) {
X    if (rBuf[i] & NES_up)
X	pPriv->dy -= pPriv->add;
X    else if (rBuf[i] & NES_down)
X	pPriv->dy += pPriv->add;
X    if (rBuf[i] & NES_right)
X	pPriv->dx += pPriv->add;
X    else if (rBuf[i] & NES_left)
X	pPriv->dx -= pPriv->add;
X    if (rBuf[i] & NES_MOVES)
X    if ((rBuf[i] & NES_MOVES) == pPriv->moves)
X        pPriv->add += pPriv->dda;			/* accelerate */
X    else
X	pPriv->add = (1 << pPriv->shift);		/* downshift */
X    pPriv->moves = (rBuf[i] & NES_MOVES);
X    if ((rBuf[i] & (NES_SWITCHES)) != pPriv->switches) {
X      pPriv->buttons = 0;
X      if (rBuf[i] & NES_A)
X	pPriv->buttons |= pPriv->A;
X      if (rBuf[i] & NES_B)
X	pPriv->buttons |= pPriv->B;
X      if (rBuf[i] & NES_select)
X	pPriv->buttons |= pPriv->Select;
X      if (rBuf[i] & NES_start)
X	pPriv->buttons |= pPriv->Start;
X      /*
X       * No AB support yet.  I don't like state machine system above.
X       * It really needs to be sub-second timer-based.
X       */
X      pPriv->switches = rBuf[i] & (NES_SWITCHES);
X      doinput++;
X    }
X    X386MouseEvent(pMouse, pPriv->buttons, 
X	pPriv->dx >> pPriv->shift, pPriv->dy >> pPriv->shift);
X    pPriv->dx = pPriv->dy = 0;
X  }
X}
X
X
X/*
X *-----------------------------------------------------------------------
X * NesMouseConfig --
X *	Read the configuration of a NesMouse.
X *
X * Results:
X *	A pointer to the allocated device.
X *
X * Side Effects:
X *
X *-----------------------------------------------------------------------
X */
X
XX386DevicePtr
XNesMouseConfig()
X{
X  NesMousePtr dev;
X  char *cp, *cp2, *strchr();
X  int i;
X
X  TRACE( ("NesMouseConfig()\n") );
X
X  if (X386Lex(NULL) != STRING)
X    FatalError("Devicename expected (%d)\n",X386LineNo);
X
X  /* Reverse convention from above */
X  dev = (NesMousePtr)xalloc(sizeof(NesMouseRec));
X  ((X386DevicePtr)dev)->deviceProc   = NesMouseProc;
X  ((X386DevicePtr)dev)->deviceEvents = NesMouseProcessEvents;
X  ((X386DevicePtr)dev)->type = "MOUSE";
X  ((X386DevicePtr)dev)->Name = X386Val.str;
X
X  /* Read in Nintendo sub-configuration */
X  /* Syntax: button[,button].. " " */
X  /* The keyword parser doesn't handle ,'s and I'm too lazy */
X  dev->A = dev->B = dev->Start = dev->Select = dev->AB = 0;
X  for(i = 2; i >= 0; i--) {
X    if (X386Lex(NULL) != STRING)
X      FatalError("Nintendo button name expected (%d)\n",X386LineNo);
X    cp = X386Val.str;
X    if (cp2 = strchr(cp, ','))
X	*cp2 = '\0';
X    while(cp && *cp) {
X      if (streq(cp, "A")) {
X	  if (dev->A)
X	      FatalError("Nintendo A button already assigned\n");
X	  else dev->A = (1<<i);
X      } else if (streq(cp, "B")) {
X	  if (dev->B)
X	      FatalError("Nintendo B button already assigned\n");
X	  else dev->B = (1<<i);
X      } else if (streq(cp, "Start")) {
X	  if (dev->Start)
X	      FatalError("Nintendo Start button already assigned\n");
X	  else dev->Start = (1<<i);
X      } else if (streq(cp, "Select")) {
X	  if (dev->Select)
X	      FatalError("Nintendo Select button already assigned\n");
X	  else dev->Select = (1<<i);
X      } else if (streq(cp, "AB")) {
X	  if (dev->AB)
X	      FatalError("Nintendo A+B button combination already assigned\n");
X	  else dev->AB = (1<<i);
X      } else 
X          FatalError("Nintendo button '%s' not recognized!\n", cp);
X      /* Advance to next Nintendo button for this mouse button */
X      if (cp2) {
X	*cp2++ = ',';	/* restore char to avoid memory leak */
X        cp = cp2;
X      } else
X        cp = 0;
X      }
X  }
X  /* optional DDA argument:  */
X  dev->dda = 0;
X  if ((X386Lex(NULL) == NUMBER) && (X386Val.num >= 0) && (X386Val.num <= 20))
X	dev->dda = X386Val.num;
X  return (X386DevicePtr)dev;
X}
X
SHAR_EOF
chmod 0644 mouseX386.c ||
echo 'restore of mouseX386.c failed'
Wc_c="`wc -c < 'mouseX386.c'`"
test 21649 -eq "$Wc_c" ||
	echo 'mouseX386.c: original size 21649, current size' "$Wc_c"
fi
# ============= nintendo.h ==============
if test -f 'nintendo.h' -a X"$1" != X"-c"; then
	echo 'x - skipping nintendo.h (File already exists)'
else
echo 'x - extracting nintendo.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'nintendo.h' &&
X
X#define	NES_right	0x01
X#define	NES_left	0x02
X#define	NES_down	0x04
X#define	NES_up		0x08
X#define	NES_start	0x10
X#define	NES_select	0x20
X#define	NES_B		0x40
X#define	NES_A		0x80
X
X#define	NES_SWITCHES	(NES_start | NES_select | NES_A | NES_B)
X#define	NES_MOVES	(NES_right | NES_left | NES_up | NES_down)
X
SHAR_EOF
chmod 0644 nintendo.h ||
echo 'restore of nintendo.h failed'
Wc_c="`wc -c < 'nintendo.h'`"
test 301 -eq "$Wc_c" ||
	echo 'nintendo.h: original size 301, current size' "$Wc_c"
fi
# ============= Node ==============
if test -f 'Node' -a X"$1" != X"-c"; then
	echo 'x - skipping Node (File already exists)'
else
echo 'x - extracting Node (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Node' &&
Xnes	nes0	c	0
SHAR_EOF
chmod 0644 Node ||
echo 'restore of Node failed'
Wc_c="`wc -c < 'Node'`"
test 13 -eq "$Wc_c" ||
	echo 'Node: original size 13, current size' "$Wc_c"
fi
# ============= System ==============
if test -f 'System' -a X"$1" != X"-c"; then
	echo 'x - skipping System (File already exists)'
else
echo 'x - extracting System (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'System' &&
Xnes	Y	1	0	0	0	378	37f	0	0
SHAR_EOF
chmod 0644 System ||
echo 'restore of System failed'
Wc_c="`wc -c < 'System'`"
test 26 -eq "$Wc_c" ||
	echo 'System: original size 26, current size' "$Wc_c"
fi
# ============= Master ==============
if test -f 'Master' -a X"$1" != X"-c"; then
	echo 'x - skipping Master (File already exists)'
else
echo 'x - extracting Master (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Master' &&
Xnes	I	icS		nes	0	XX	1	255	-1
X						^ major device number goes here
SHAR_EOF
chmod 0644 Master ||
echo 'restore of Master failed'
Wc_c="`wc -c < 'Master'`"
test 67 -eq "$Wc_c" ||
	echo 'Master: original size 67, current size' "$Wc_c"
fi
exit 0
-- 
Lance
THES IZ BENITO AGEN. WEE AR STUK SUMWERE IN TEKSUS. WEE AR LOST. I OFURRED
THE MAP TOO CAESAR THRE TIMES, END THRICE HEE REFUZED ITT. THERFORE, I
REMANED NAVIGATER.  - BENITO, alt.culture.electric-midget.classics