From: Andrew Hobson (gt6698a@prism.gatech.EDU)
Date: 08/27/92


From: gt6698a@prism.gatech.EDU (Andrew Hobson)
Subject: Microsoft Bus mouse works, sorta
Date: 27 Aug 1992 18:41:44 GMT


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