From: gt6698a@prism.gatech.EDU (Andrew Hobson)
Newsgroups: comp.os.linux
Subject: Microsoft Bus mouse works, sorta
Summary: microsoft bus mouse works, sorta
Keywords: microsoft, bus
Date: 27 Aug 92 18:41:44 GMT
Organization: Georgia Institute of Technology


Greets!

I have an ATI VGA Wonder XL and I have a microsoft mouse plugged in the 
bus port. (It is on the VGA card)  Rik Faith (faith@cs.unc.edu) has
written a X386 for ATI cards and it works great, I think. 

I received mail from Derrick C. Cole <cole@concert.net> when I posted
previously about getting the microsoft bus mouse to work.  He mailed
me a patch by Frank ten Wolde (franky@duteca.et.tudelft.nl). 
I have modified this patch and the existing mouse.c by
James Banks, David Giller, and Nathan Laredo (Thanks for the help,
Nathan!!!)

I have made modifications to mouse.c so that a microsoft mouse will 
work.  Essentially, these changes were only to the mouse_interrupt 
function and should not have affected anything else.  If I run X, then 
my mouse will not work, even though I am pretty sure that the mouse 
driver works.  (I put printk's inside the driver, and I modified the 
mouse test program that comes with X for use with a bus mouse and it
works)  If I run a program that does an ioperm(port,1,1) for all 
four of the port addresses, and then run X, I can use the mouse 
until the xterm comes up.  Then, as long as I hold down a key 
(on the keyboard), the mouse works.  If I do not hold down a key, 
then move the mouse, and then press a key, the mouse will jump 
to a new location, about where it should have moved.  (I have no 
way of telling exactly where it should have moved.)  If I get 
rid of the Xterm and Xclock, I still cannot use the mouse, 
except by pressing down a key.  Pressing a mouse button does not 
register, unless the mouse is moved.  Using the mouse program that came with X, if I press a button, then new information
is printed on the screen, but is is the same information as before until
I move the mouse. 

I guess I need some testers to see if the problem is with the ATI
X or with my code.  

I have sent mail to Rik Faith about this, as well, so hopefully this 
can be resolved.  I would really like to not have to press a key
to use my mouse in X!!

Thanks alot for any help you can give me. I will include copies of my 
/usr/src/linux/kernel/chr_drv/mouse.c and 
/usr/src/linux/include/linux/mouse.h files.   I don't think that I have
changed mouse.h. I can't post a patch because
I am not sure I have the original I have done so many changes!!

Andrew Hobson

/*======================  MOUSE.C  =========================*/

/*
 * Logitech Bus Mouse Driver for Linux
 * by James Banks
 * 
 * Heavily modified by David Giller
 *   changed from queue- to counter- driven
 *   hacked out a (probably incorrect) mouse_select
 *
 * Modified again by Nathan Laredo to interface with
 *   0.96c-pl1 IRQ handling changes (13JUL92)
 *   didn't bother touching select code.
 * 
 * version 0.1
 */

/* Modified to work with microsoft bus mice.  Might work, might not */
/* Andrew Hobson gt6698a@prism.gatech.edu 27AUG92 */

#include	<linux/kernel.h>
#include	<linux/sched.h>
#include	<linux/tty.h>
#include	<asm/io.h>
#include	<asm/segment.h>
#include	<asm/system.h>
#include	<asm/irq.h>
#include	<linux/errno.h>
#include	<linux/signal.h>
#include	<linux/mouse.h>

struct mouse_status mouse;

void release_mouse(struct inode * inode, struct file * file)
{
	MSE_INT_OFF();
	mouse.active = 0;
	mouse.ready = 0; 
	mouse.inode = NULL;
	
	free_irq(MOUSE_IRQ);
}

int open_mouse(struct inode * inode, struct file * file)
{
	if (mouse.active) return -EBUSY;
	if (!mouse.present) return -EINVAL;
	
	mouse.active = 1;
	mouse.ready = 0;
	mouse.inode = inode;
	mouse.dx = 0;
	mouse.dy = 0;	
	mouse.buttons = mouse.latch_buttons = 0x80;
	
	
	MSE_INT_ON();
	if (request_irq(MOUSE_IRQ, mouse_interrupt)) return -EBUSY;

	return 0;
}

int write_mouse(struct inode * inode, struct file * file,
		char * buffer, int count)
{
	return -EINVAL;
}

int read_mouse(struct inode * inode, struct file * file, 
		char * buffer, int count)
{
	int i;

	if (count < 3) return -EINVAL;
	if (!mouse.ready) return -EAGAIN;
	
	MSE_INT_OFF();
		
	put_fs_byte(mouse.latch_buttons | 0x80, buffer); 
	
	if (mouse.dx < -127) mouse.dx = -127;
	if (mouse.dx >  127) mouse.dx =  127;
	
	put_fs_byte((char)mouse.dx, buffer + 1);
	
	if (mouse.dy < -127) mouse.dy = -127;
	if (mouse.dy >  127) mouse.dy =  127;
	
	put_fs_byte((char) -mouse.dy, buffer + 2);
	
	for (i = 3; i < count; i++)
		put_fs_byte(0x00, buffer + i);

	mouse.dx = 0;
	mouse.dy = 0;
	mouse.latch_buttons = mouse.buttons;
	mouse.ready = 0;
	
	MSE_INT_ON();
	return i;	
}

#define outp(a,b)	outb(b,a);

void mouse_interrupt(void)
{
	char dx, dy, buttons;
	unsigned int i;
 	char tmp;

	MSE_INT_OFF();

        outp(MSE_DATA_PORT, 0x07);          /* from MSDOS device driver */
        outp(MSE_SIGNATURE_PORT, tmp = (inb(MSE_SIGNATURE_PORT) | 0x20));

        /* FTW  version 0.2  920614:
         * I have seen this in the MSDOS Microsoft Bus Mouse device driver.
         * Don't know what its for. It does not seem required as it works
         * well as it is!
         */
        if (0) {
            /* I hope GCC is clever enough to just to remove this code :-) */
	    (void) inb(MSE_SIGNATURE_PORT);
	    (void) inb(MSE_SIGNATURE_PORT);
	    (void) inb(MSE_SIGNATURE_PORT);
	    outp(MSE_SIGNATURE_PORT, tmp);
	}

        outp(MSE_DATA_PORT, 0x01);          /* from MSDOS device driver */
        dx = inb(MSE_SIGNATURE_PORT);

        outp(MSE_DATA_PORT, 0x02);          /* from MSDOS device driver */
        dy = inb(MSE_SIGNATURE_PORT);

        outp(MSE_DATA_PORT, 0x00);          /* from MSDOS device driver */
        buttons = inb(MSE_SIGNATURE_PORT);

        outp(MSE_DATA_PORT, 0x07);          /* from MSDOS device driver */
        outp(MSE_SIGNATURE_PORT, inb(MSE_SIGNATURE_PORT) & 0xDF);

        /* FTW  version 0.2  920614:
         * Ah! The microsoft mouse has its buttons reversed with respect
         * to the Logitech Mouse. You certainly get very strange mouse
         * behaviour in X with the buttons reversed :-)
         */
        buttons = ~buttons;
        buttons &= 0x07;        /* ignore button state change info      */

        /* FTW  version 0.2  920614
         * Another thing: The original code for do_IRQ5 simply returned
         * immediately if the event_queue was full. This does not work
         * for Microsoft as the mouse requires to be 'flushed.' The behaviour
         * in X was that after violent mouse movements it would simply freeze
         * up and remained dead until after a system reboot. Hence the
         * !queuefull test at this point in the code.
         */

        /* FTW  version 0.2  920614
         * The following outb() instruction probably does nothing for the
         * Microsoft Mouse. It is a left over from the Logitech code.
         */
	MSE_INT_ON();

	mouse.buttons = buttons;
	mouse.latch_buttons |= buttons;
	mouse.dx += dx;
	mouse.dy += dy;
	mouse.ready = 1;
	if (mouse.inode && mouse.inode->i_wait)
	         wake_up(&mouse.inode->i_wait);

}

	
static struct file_operations mouse_fops = {
        NULL,		/* mouse_seek */
        read_mouse,
        write_mouse,
        NULL, 		/* mouse_readdir */
        mouse_select, 	/* mouse_select */
        NULL, 		/* mouse_ioctl */
        open_mouse,
        release_mouse,
};

int mouse_select(struct inode *inode, struct file *file, int which, 
		select_table *seltable)
{
        if (mouse.ready) 
	   return 1;
	else
	   return 0;
}

long mouse_init(long kmem_start)
{	
	int i,j;
	unsigned char tchar;
	
	outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT);
	outb(0x09, MSE_SIGNATURE_PORT);

	for (i = 0; i < 100000; i++); /* busy loop */
        tchar = inb(MSE_SIGNATURE_PORT);
	if (tchar != (0x09)) {
		printk("No bus mouse detected.\n");
		mouse.present = 0;
		return kmem_start;
	}
        chrdev_fops[10] = &mouse_fops;

	mouse.present = 1;
	mouse.active = 0;
	mouse.ready = 0;
	mouse.buttons = mouse.latch_buttons = 0x80;
	mouse.dx = 0;
	mouse.dy = 0;
	printk("Bus mouse detected and installed.\n");
	return kmem_start;
}



/* ============================== MOUSE.H ========================== */

/*
 * linux/include/linux/mouse.h: header file for Logitech Bus Mouse driver
 * by James Banks
 *
 * based on information gleamed from various mouse drivers on the net
 *
 * Heavily modified by David giller (rafetmad@oxy.edu)
 *
 * Minor modifications for Linux 0.96c-pl1 by Nathan Laredo
 * gt7080a@prism.gatech.edu (13JUL92)
 *
 */

#ifndef _MOUSE_H
#define _MOUSE_H

#define MOUSE_IRQ		5

#define	MSE_DATA_PORT		0x23c
#define	MSE_SIGNATURE_PORT	0x23d
#define	MSE_CONTROL_PORT	0x23e
#define MSE_INTERRUPT_PORT	0x23e
#define	MSE_CONFIG_PORT		0x23f

#define	MSE_ENABLE_INTERRUPTS	0x00
#define	MSE_DISABLE_INTERRUPTS	0x10

#define	MSE_READ_X_LOW		0x80
#define	MSE_READ_X_HIGH		0xa0
#define	MSE_READ_Y_LOW		0xc0
#define	MSE_READ_Y_HIGH		0xe0

/* Magic number used to check if the mouse exists */
#define MSE_CONFIG_BYTE		0x91
#define MSE_DEFAULT_MODE	0x90
#define MSE_SIGNATURE_BYTE	0xa5

/* useful macros */

#define MSE_INT_OFF()	outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT)
#define MSE_INT_ON()	outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT)
 
struct mouse_status
	{
	char		buttons;
	char		latch_buttons;
	int		dx;
	int		dy;	

	int 		present;
	int		ready;
	int		active;

	struct inode    *inode;
	};

/* Function Prototypes */
extern void mouse_interrupt(void);
extern long mouse_init(long);
extern int open_mouse(struct inode *, struct file *);
extern void release_mouse(struct inode *, struct file *);
extern int read_mouse(struct inode *, struct file *, char *, int);
extern int write_mouse(struct inode *, struct file *, char *, int);
extern int mouse_select(struct inode *inode, struct file *file, int which, 
		select_table *seltable);
#endif



-- 
Andrew Hobson                         Internet: gt6698a@prism.gatech.edu
"He who joyfully marches to music in rank and file has already
earned my contempt.  He has been given a large brain by mistake,
since for him the spinal cord would fully suffice."   -- Albert Einstein
Newsgroups: comp.os.linux