mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
419 lines
10 KiB
419 lines
10 KiB
#include "insignia.h"
|
|
#include "host_def.h"
|
|
/*
|
|
* SoftPC Version 2.0
|
|
*
|
|
* Title : Microsoft Bus Mouse Adapter
|
|
*
|
|
* Description : This package contains a group of functions that provide
|
|
* an interface between the Microsoft Bus Mouse Card and the cpu.
|
|
*
|
|
* mouse_init() Initialise the bus mouse adapter
|
|
* mouse_inb() Supports IN's from ports in the bus mouse range
|
|
* mouse_outb() Supports OUT's to ports in the bus mouse range
|
|
* mouse_send() Queues data sent from the host mouse
|
|
*
|
|
* Author : Henry Nash
|
|
*
|
|
* Notes : See the Microsoft Inport Technical Reference Manual for
|
|
* further information on the hardware interface.
|
|
* The Bus Mouse ports are jumper selectable on the real card
|
|
* between (1) 023C - 023F & (2) 0238 - 023B. We only support
|
|
* the primary range 023C - 023F.
|
|
*
|
|
* (r3.5) : The system directory /usr/include/sys is not available
|
|
* on a Mac running Finder and MPW. Bracket references to
|
|
* such include files by "#ifdef macintosh <Mac file> #else
|
|
* <Unix file> #endif".
|
|
*/
|
|
|
|
#ifdef SCCSID
|
|
static char SccsID[]="@(#)mouse.c 1.17+ 07/10/95 Copyright Insignia Solutions Ltd.";
|
|
#endif
|
|
|
|
#ifdef SEGMENTATION
|
|
/*
|
|
* The following #include specifies the code segment into which this
|
|
* module will by placed by the MPW C compiler on the Mac II running
|
|
* MultiFinder.
|
|
*/
|
|
#include "SOFTPC_MOUSE.seg"
|
|
#endif
|
|
|
|
|
|
/*
|
|
* O/S include files.
|
|
*/
|
|
#include <stdio.h>
|
|
#include TypesH
|
|
|
|
/*
|
|
* SoftPC include files
|
|
*/
|
|
#include "xt.h"
|
|
#include CpuH
|
|
#include "sas.h"
|
|
#include "cga.h"
|
|
#include "bios.h"
|
|
#include "error.h"
|
|
#include "ios.h"
|
|
#include "ica.h"
|
|
#include "trace.h"
|
|
#include "video.h"
|
|
#include "mouse.h"
|
|
#include "mouse_io.h"
|
|
|
|
|
|
/*
|
|
* The following globals are also used by xxx_input.c,
|
|
* where xxx is the host machine name.
|
|
*/
|
|
|
|
int button_left = 0; /* Current state of left button */
|
|
int button_right = 0; /* Current state of right button */
|
|
int delta_x = 0, delta_y = 0; /* Current mouse delta moves */
|
|
|
|
#ifndef PROD
|
|
static char buff[132];
|
|
#endif
|
|
|
|
static half_word data1_reg = 0,
|
|
data2_reg = 0,
|
|
mouse_status_reg = 0;
|
|
|
|
static half_word
|
|
last_button_left = 0,
|
|
last_button_right = 0;
|
|
|
|
static half_word
|
|
mouse_mode_reg = 0, /* mode register */
|
|
address_reg = 0; /* address pointer register */
|
|
|
|
static int
|
|
loadsainterrupts = 5;
|
|
/* count of how many times we will send bursts of interrupts to please Windows, per reset */
|
|
|
|
|
|
static int mouse_inb_toggle = 0;
|
|
|
|
void mouse_inb IFN2(io_addr, port, half_word *, value)
|
|
{
|
|
if (port == MOUSE_PORT_1) { /* data register */
|
|
|
|
/*
|
|
* Internal registers
|
|
*/
|
|
|
|
switch (address_reg & 0x07) {
|
|
case 0x00 : /* mouse status register */
|
|
*value = mouse_status_reg;
|
|
break;
|
|
case 0x01 : /* data 1 register horizontal */
|
|
*value = data1_reg;
|
|
break;
|
|
case 0x02 : /* data 2 register vertical */
|
|
*value = data2_reg;
|
|
break;
|
|
case 0x07 : /* mode register */
|
|
*value = mouse_mode_reg;
|
|
break;
|
|
default :
|
|
#ifndef PROD
|
|
if (io_verbose & MOUSE_VERBOSE) {
|
|
sprintf(buff, "mouse_inb() : Bad P");
|
|
trace(buff,DUMP_NONE);
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* ID register, alternates between value 1 and value 2
|
|
* value 1 is the chip signature: DE hex
|
|
* value 2 is the chip revision: 1 and version: 0
|
|
*/
|
|
|
|
else
|
|
if (port == MOUSE_PORT_2) {
|
|
if (mouse_inb_toggle = 1 - mouse_inb_toggle)
|
|
*value = 0xDE;
|
|
else
|
|
*value = 0x10;
|
|
}
|
|
|
|
#ifndef PROD
|
|
if (io_verbose & MOUSE_VERBOSE) {
|
|
sprintf(buff, "mouse_inb() : port %x value %x", port, *value);
|
|
trace(buff,DUMP_NONE);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
void mouse_outb IFN2(io_addr, port, half_word, value)
|
|
{
|
|
#ifndef PROD
|
|
if (io_verbose & MOUSE_VERBOSE) {
|
|
if ((port == MOUSE_PORT_0)
|
|
|| (port == MOUSE_PORT_1)
|
|
|| (port == MOUSE_PORT_2))
|
|
sprintf(buff, "mouse_outb() : port %x value %x", port, value);
|
|
else
|
|
sprintf(buff, "mouse_outb() : bad port: %x value %x", port, value);
|
|
trace(buff,DUMP_NONE);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Out to an internal register
|
|
*/
|
|
|
|
if (port == MOUSE_PORT_1) { /* data register */
|
|
|
|
/*
|
|
* Out to Mode register
|
|
*/
|
|
if ( (address_reg & 0x07) == INTERNAL_MODE_REG) {
|
|
|
|
/*
|
|
* Check hold bit (5) for 0 to 1 transition
|
|
* - Data Interrupt Enable bit is set (Mode 0)
|
|
* - counter values saved in Data1 & Data2 registers (Mode 0)
|
|
* - counters cleared
|
|
* - status register updated
|
|
*/
|
|
|
|
if ((value & 0x20) && ((mouse_mode_reg & 0x20) == 0)) {
|
|
#ifndef PROD
|
|
if (io_verbose & MOUSE_VERBOSE) {
|
|
sprintf(buff, "mouse_outb() : hold bit 0 -> 1");
|
|
trace(buff,DUMP_NONE);
|
|
}
|
|
#endif
|
|
/* clear the interrupt */
|
|
ica_clear_int(AT_CPU_MOUSE_ADAPTER, AT_CPU_MOUSE_INT);
|
|
|
|
/*
|
|
* read next mouse deltas & buttons
|
|
* into the inport registers
|
|
*/
|
|
data1_reg = delta_x;
|
|
data2_reg = delta_y;
|
|
mouse_status_reg = 0;
|
|
mouse_status_reg = (button_left << 2) + (button_right);
|
|
if (delta_x!=0 || delta_y!=0) {
|
|
mouse_status_reg |= MOVEMENT;
|
|
}
|
|
if (last_button_right != button_right) {
|
|
mouse_status_reg |= RIGHT_BUTTON_CHANGE;
|
|
last_button_right = button_right;
|
|
}
|
|
|
|
if (last_button_left != button_left) {
|
|
mouse_status_reg |= LEFT_BUTTON_CHANGE;
|
|
last_button_left = button_left;
|
|
}
|
|
delta_x = delta_y = 0;
|
|
}
|
|
/* 1 -> 0 transition on mode register's hold bit */
|
|
/* ready for next read from queue, so send interrupt */
|
|
else if ((mouse_mode_reg & 0x20) && ((value & 0x20)==0)){
|
|
#ifndef PROD
|
|
if (io_verbose & MOUSE_VERBOSE) {
|
|
sprintf(buff, "mouse_outb() : hold bit 1 -> 0");
|
|
trace(buff,DUMP_NONE);
|
|
}
|
|
#endif
|
|
}
|
|
/*
|
|
* Check timer select value (bits 210)
|
|
*/
|
|
|
|
switch (value & 0x7) {
|
|
case 0x0 : /* 0 Hz INTR low */
|
|
#ifndef PROD
|
|
if (io_verbose & MOUSE_VERBOSE) {
|
|
sprintf(buff, "mouse_outb() : INTR low"); trace(buff,DUMP_NONE);
|
|
}
|
|
#endif
|
|
ica_clear_int(AT_CPU_MOUSE_ADAPTER, AT_CPU_MOUSE_INT);
|
|
break;
|
|
|
|
/*
|
|
* In the following cases the application code is expecting to see
|
|
* interrupts at the requested rate. However in practice this is only
|
|
* required during initialisation(mouse_mode_reg = 0), and then a short burst
|
|
* appears to be sufficient. The 15 interupts generated comes from
|
|
* tests with the "WINDOWS" package, which receives about 15 during
|
|
* initialising, but is happy as long as it gets more than 3. The delay
|
|
* is necessary otherwise the interupts are generated before the
|
|
* application starts looking for them.
|
|
|
|
* Mark 2 bodge:
|
|
Windows 1.02 needs the burst of interrupts to occur even when mouse_mode_reg != 0,
|
|
but Windows 2.03 needs them not to keep happening even when it asks for them.
|
|
So now there's a counter called loadsainterrupts set to 5 on resets, which is
|
|
how many bursts will be allowed. This makes both Windows work.
|
|
*/
|
|
case 0x1: /* 30 Hz */
|
|
case 0x2: /* 50 Hz */
|
|
case 0x3: /* 100 Hz */
|
|
case 0x4: /* 200 Hz */
|
|
/* used to be if mouse_mode_reg == 0 too, removed to make Windows 1.02 work */
|
|
if( (value & 0x10) && loadsainterrupts > 0)
|
|
{
|
|
loadsainterrupts--;
|
|
#ifndef PROD
|
|
if (io_verbose & MOUSE_VERBOSE) {
|
|
sprintf(buff, "mouse_outb() : Loadsainterrupts"); trace(buff,DUMP_NONE);
|
|
}
|
|
#endif
|
|
/*
|
|
** AT version is asking for a 100 interrupts.
|
|
** The AT ica does not handle delayed ints so
|
|
** the IRET has been modified to not allow an
|
|
** int to go off before the next instruction.
|
|
*/
|
|
ica_hw_interrupt(AT_CPU_MOUSE_ADAPTER,AT_CPU_MOUSE_INT,100);
|
|
}
|
|
break;
|
|
case 0x5: /* reserved */
|
|
#ifndef PROD
|
|
if (io_verbose & MOUSE_VERBOSE) {
|
|
sprintf(buff, "mouse: reserved"); trace(buff,DUMP_NONE);
|
|
}
|
|
#endif
|
|
break;
|
|
case 0x6 : /* 0 Hz INTR hi */
|
|
#ifndef PROD
|
|
if (io_verbose & MOUSE_VERBOSE) {
|
|
sprintf(buff, "mouse_outb() : INTR hi"); trace(buff,DUMP_NONE);
|
|
}
|
|
#endif
|
|
ica_hw_interrupt(AT_CPU_MOUSE_ADAPTER,AT_CPU_MOUSE_INT,1);
|
|
break;
|
|
case 0x7: /* externally controlled */
|
|
break;
|
|
default:
|
|
#ifndef PROD
|
|
if (io_verbose & MOUSE_VERBOSE) {
|
|
sprintf(buff,"mouse_outb() : bad mode");
|
|
trace(buff,DUMP_NONE);
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
}
|
|
mouse_mode_reg = value;
|
|
|
|
/*
|
|
* Interface control register
|
|
*/
|
|
}
|
|
else
|
|
if ((address_reg & 0x07) == INTERFACE_CONTROL_REG){
|
|
#ifndef PROD
|
|
if (io_verbose & MOUSE_VERBOSE) {
|
|
sprintf(buff, "mouse_outb() : interface control reg port %x value %x",port,value);
|
|
trace(buff,DUMP_NONE);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
}
|
|
else if(port == MOUSE_PORT_0) /* address pointer register */
|
|
{
|
|
if (value & 0x80) /* is it a reset */
|
|
{
|
|
mouse_mode_reg = 0;
|
|
loadsainterrupts = 5; /* lets Windows initialise its mouse happily */
|
|
address_reg = value & 0x7F; /* clear reset bit*/
|
|
ica_clear_int( AT_CPU_MOUSE_ADAPTER, AT_CPU_MOUSE_INT );
|
|
}
|
|
else
|
|
address_reg = value;
|
|
}
|
|
}
|
|
|
|
#ifdef SEGMENTATION
|
|
/*
|
|
* The following #include specifies the code segment into which this
|
|
* module will by placed by the MPW C compiler on the Mac II running
|
|
* MultiFinder.
|
|
*/
|
|
#include "SOFTPC_INPUT.seg"
|
|
#endif
|
|
|
|
void mouse_send(Delta_x,Delta_y,left,right)
|
|
int Delta_x,Delta_y,left,right;
|
|
{
|
|
if(Delta_x != 0 || Delta_y != 0 || button_left != left || button_right != right)
|
|
{
|
|
delta_x += Delta_x;
|
|
delta_y += Delta_y;
|
|
|
|
/***
|
|
Mouse inport registers can only handle one byte
|
|
***/
|
|
if (delta_x < -128)
|
|
delta_x = -128;
|
|
else if (delta_x > 127)
|
|
delta_x = 127;
|
|
|
|
if (delta_y < -128)
|
|
delta_y = -128;
|
|
else if (delta_y > 127)
|
|
delta_y = 127;
|
|
|
|
button_left = left;
|
|
button_right = right;
|
|
ica_hw_interrupt(AT_CPU_MOUSE_ADAPTER,AT_CPU_MOUSE_INT,1);
|
|
}
|
|
}
|
|
|
|
#ifdef SEGMENTATION
|
|
/*
|
|
* The following #include specifies the code segment into which this
|
|
* module will by placed by the MPW C compiler on the Mac II running
|
|
* MultiFinder.
|
|
*/
|
|
#include "SOFTPC_INIT.seg"
|
|
#endif
|
|
|
|
|
|
void mouse_init IFN0()
|
|
{
|
|
int p;
|
|
|
|
#ifndef PROD
|
|
if (io_verbose & MOUSE_VERBOSE) {
|
|
sprintf(buff, "mouse_init()");
|
|
trace(buff,DUMP_NONE);
|
|
}
|
|
#endif
|
|
|
|
mouse_inb_toggle = 0;
|
|
|
|
io_define_inb(MOUSE_ADAPTOR, mouse_inb);
|
|
io_define_outb(MOUSE_ADAPTOR, mouse_outb);
|
|
|
|
for(p = MOUSE_PORT_START; p <= MOUSE_PORT_END; p++) {
|
|
io_connect_port(p, MOUSE_ADAPTOR, IO_READ_WRITE);
|
|
|
|
#ifdef KIPPER
|
|
#ifdef CPU_40_STYLE
|
|
/* Enable iret hooks on mouse interrupts */
|
|
ica_iret_hook_control(AT_CPU_MOUSE_ADAPTER, AT_CPU_MOUSE_INT, TRUE);
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef PROD
|
|
if (io_verbose & MOUSE_VERBOSE) {
|
|
sprintf(buff, "Mouse Port connected: %x", p);
|
|
trace(buff,DUMP_NONE);
|
|
}
|
|
#endif
|
|
}
|
|
host_deinstall_host_mouse();
|
|
}
|