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.
1021 lines
29 KiB
1021 lines
29 KiB
#include "insignia.h"
|
|
#include "host_def.h"
|
|
/*[
|
|
* Name: ios.c
|
|
*
|
|
* Author: Wayne Plummer
|
|
*
|
|
* Created: 7th February 1991
|
|
*
|
|
* Sccs ID: @(#)ios.c 1.29 09/27/94
|
|
*
|
|
* Purpose: This module provides a routing mechanism for Input and Ouput
|
|
* requests.
|
|
*
|
|
* (c)Copyright Insignia Solutions Ltd., 1991. All rights reserved.
|
|
]*/
|
|
|
|
#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_IOS.seg"
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
/*
|
|
* SoftPC include files
|
|
*/
|
|
#include "xt.h"
|
|
#include CpuH
|
|
#include "ios.h"
|
|
#include "trace.h"
|
|
#include "debug.h"
|
|
#include "sas.h"
|
|
#include MemoryH
|
|
|
|
#if defined(SPC386) && !defined(GISP_CPU)
|
|
#define VIRTUALISATION
|
|
#endif
|
|
|
|
#ifdef NTVDM
|
|
#define getIOInAdapter(ioaddr) (Ios_in_adapter_table[ioaddr & (PC_IO_MEM_SIZE-1)])
|
|
#define getIOOutAdapter(ioaddr) (Ios_out_adapter_table[ioaddr & (PC_IO_MEM_SIZE-1)])
|
|
#endif
|
|
|
|
/*
|
|
*
|
|
* ============================================================================
|
|
* Global data
|
|
* ============================================================================
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Ios_in_adapter_table & Ios_out_adapter_table - These tables give the association
|
|
* between the IO address used for an IO and the SoftPC adapter ID associated with the
|
|
* IO subroutines.
|
|
*
|
|
* Note that there are two tables here to allow for memory mapped IO locations which
|
|
* have an input functionality which is unrelated to the output functionality...
|
|
* In these cases, two connect port calls to the same IO address would be made, one with
|
|
* only the IO_READ flag set, the other with only the IO_WRITE flag set.
|
|
*/
|
|
#ifdef MAC68K
|
|
GLOBAL char *Ios_in_adapter_table = NULL;
|
|
GLOBAL char *Ios_out_adapter_table = NULL;
|
|
#else
|
|
GLOBAL char Ios_in_adapter_table[PC_IO_MEM_SIZE];
|
|
GLOBAL char Ios_out_adapter_table[PC_IO_MEM_SIZE];
|
|
#endif /* MAC68K */
|
|
#ifndef PROD
|
|
GLOBAL IU32 *ios_empty_in = (IU32 *)0;
|
|
GLOBAL IU32 *ios_empty_out = (IU32 *)0;
|
|
#endif /* PROD */
|
|
|
|
/*
|
|
* Ios_xxx_function - These tables are indexed by the adapter ID obtained
|
|
* from the Ios_in_adapter_table or Ios_in_adapter_table to yield a pointer
|
|
* to the IO routine to call.
|
|
*/
|
|
typedef void (*IOS_FUNC_INB) IPT2(io_addr, io_address, half_word *, value);
|
|
typedef void (*IOS_FUNC_INW) IPT2(io_addr, io_address, word *, value);
|
|
typedef void (*IOS_FUNC_INSB) IPT3(io_addr, io_address, half_word *, valarray, word, count);
|
|
typedef void (*IOS_FUNC_INSW) IPT3(io_addr, io_address, word *, valarray, word, count);
|
|
typedef void (*IOS_FUNC_OUTB) IPT2(io_addr, io_address, half_word, value);
|
|
typedef void (*IOS_FUNC_OUTW) IPT2(io_addr, io_address, word, value);
|
|
typedef void (*IOS_FUNC_OUTSB) IPT3(io_addr, io_address, half_word *, valarray, word, count);
|
|
typedef void (*IOS_FUNC_OUTSW) IPT3(io_addr, io_address, word *, valarray, word, count);
|
|
#ifdef SPC386
|
|
typedef void (*IOS_FUNC_IND) IPT2(io_addr, io_address, double_word *, value);
|
|
typedef void (*IOS_FUNC_INSD) IPT3(io_addr, io_address, double_word *, valarray, word, count);
|
|
typedef void (*IOS_FUNC_OUTD) IPT2(io_addr, io_address, double_word, value);
|
|
typedef void (*IOS_FUNC_OUTSD) IPT3(io_addr, io_address, double_word *, valarray, word, count);
|
|
#endif
|
|
|
|
LOCAL void generic_inw IPT2(io_addr, io_address, word *, value);
|
|
LOCAL void generic_insb IPT3(io_addr, io_address, half_word *, valarray, word, count);
|
|
LOCAL void generic_insw IPT3(io_addr, io_address, word *, valarray, word, count);
|
|
LOCAL void generic_outw IPT2(io_addr, io_address, word, value);
|
|
LOCAL void generic_outsb IPT3(io_addr, io_address, half_word *, valarray, word, count);
|
|
LOCAL void generic_outsw IPT3(io_addr, io_address, word *, valarray, word, count);
|
|
#ifdef SPC386
|
|
LOCAL void generic_ind IPT2(io_addr, io_address, double_word *, value);
|
|
LOCAL void generic_insd IPT3(io_addr, io_address, double_word *, valarray, word, count);
|
|
LOCAL void generic_outd IPT2(io_addr, io_address, double_word, value);
|
|
LOCAL void generic_outsd IPT3(io_addr, io_address, double_word *, valarray, word, count);
|
|
#endif
|
|
|
|
GLOBAL IOS_FUNC_INB Ios_inb_function [IO_MAX_NUMBER_ADAPTORS];
|
|
GLOBAL IOS_FUNC_INW Ios_inw_function [IO_MAX_NUMBER_ADAPTORS];
|
|
GLOBAL IOS_FUNC_INSB Ios_insb_function [IO_MAX_NUMBER_ADAPTORS];
|
|
GLOBAL IOS_FUNC_INSW Ios_insw_function [IO_MAX_NUMBER_ADAPTORS];
|
|
|
|
GLOBAL IOS_FUNC_OUTB Ios_outb_function [IO_MAX_NUMBER_ADAPTORS];
|
|
GLOBAL IOS_FUNC_OUTW Ios_outw_function [IO_MAX_NUMBER_ADAPTORS];
|
|
GLOBAL IOS_FUNC_OUTSB Ios_outsb_function[IO_MAX_NUMBER_ADAPTORS];
|
|
GLOBAL IOS_FUNC_OUTSW Ios_outsw_function[IO_MAX_NUMBER_ADAPTORS];
|
|
|
|
#ifdef SPC386
|
|
GLOBAL IOS_FUNC_IND Ios_ind_function [IO_MAX_NUMBER_ADAPTORS];
|
|
GLOBAL IOS_FUNC_INSD Ios_insd_function [IO_MAX_NUMBER_ADAPTORS];
|
|
GLOBAL IOS_FUNC_OUTD Ios_outd_function [IO_MAX_NUMBER_ADAPTORS];
|
|
GLOBAL IOS_FUNC_OUTSD Ios_outsd_function[IO_MAX_NUMBER_ADAPTORS];
|
|
#endif
|
|
|
|
/*
|
|
*
|
|
* ============================================================================
|
|
* Local Subroutines
|
|
* ============================================================================
|
|
*
|
|
*/
|
|
|
|
#define BIT_NOT_SET(vector, bit) \
|
|
((vector == (IU32 *)0) ? FALSE: ((((vector[(bit) >> 5]) >> ((bit) & 0x1f)) & 1) == 0))
|
|
|
|
#define SET_THE_BIT(vector, bit) \
|
|
{ \
|
|
if (vector != (IU32 *)0) \
|
|
{ \
|
|
vector[(bit) >> 5] |= (1 << ((bit) & 0x1f)); \
|
|
} \
|
|
}
|
|
|
|
/*
|
|
============================== io_empty_inb ==================================
|
|
PURPOSE:
|
|
To simulate an INB to an empty io_addr.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
*/
|
|
LOCAL void io_empty_inb IFN2(io_addr, io_address, half_word *, value)
|
|
{
|
|
#ifdef PROD
|
|
UNUSED(io_address);
|
|
|
|
#else
|
|
if (BIT_NOT_SET(ios_empty_in, (IU16)io_address))
|
|
{
|
|
/* First time for this port */
|
|
always_trace1 ("INB attempted on empty port 0x%x", io_address);
|
|
SET_THE_BIT(ios_empty_in, (IU16)io_address);
|
|
}
|
|
#endif /* PROD */
|
|
*value = IO_EMPTY_PORT_BYTE_VALUE;
|
|
}
|
|
|
|
/*
|
|
============================== io_empty_outb ==================================
|
|
PURPOSE:
|
|
To simulate an OUTB to an empty io_addr.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
*/
|
|
LOCAL void io_empty_outb IFN2(io_addr, io_address, half_word, value)
|
|
{
|
|
UNUSED(value);
|
|
#ifdef PROD
|
|
UNUSED(io_address);
|
|
#else
|
|
|
|
if (BIT_NOT_SET(ios_empty_out, (IU16)io_address))
|
|
{
|
|
/* First time for this port */
|
|
always_trace1 ("OUTB attempted on empty port 0x%x", io_address);
|
|
SET_THE_BIT(ios_empty_out, (IU16)io_address);
|
|
}
|
|
#endif /* PROD */
|
|
/* Do nothing! */
|
|
}
|
|
|
|
/*
|
|
=============================== generic_inw ==================================
|
|
PURPOSE:
|
|
To simulate an INW using the appropriate INB routine.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
*/
|
|
LOCAL void generic_inw IFN2(io_addr, io_address, word *, value)
|
|
{
|
|
reg temp;
|
|
|
|
(*Ios_inb_function[Ios_in_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]])
|
|
(io_address, &temp.byte.low);
|
|
io_address++;
|
|
(*Ios_inb_function[Ios_in_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]])
|
|
(io_address, &temp.byte.high);
|
|
#ifdef LITTLEND
|
|
*((half_word *) value + 0) = temp.byte.low;
|
|
*((half_word *) value + 1) = temp.byte.high;
|
|
#endif /* LITTLEND */
|
|
|
|
#ifdef BIGEND
|
|
*((half_word *) value + 0) = temp.byte.high;
|
|
*((half_word *) value + 1) = temp.byte.low;
|
|
#endif /* BIGEND */
|
|
}
|
|
|
|
/*
|
|
=============================== generic_outw ==================================
|
|
PURPOSE:
|
|
To simulate an OUTW using the appropriate OUTB routine.
|
|
INPUT:
|
|
OUTPUT:
|
|
Notes: GLOBAL for JOKER.
|
|
==============================================================================
|
|
*/
|
|
LOCAL void generic_outw IFN2(io_addr, io_address, word, value)
|
|
{
|
|
reg temp;
|
|
|
|
temp.X = value;
|
|
(*Ios_outb_function[Ios_out_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]])
|
|
(io_address, temp.byte.low);
|
|
++io_address;
|
|
(*Ios_outb_function[Ios_out_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]])
|
|
(io_address, temp.byte.high);
|
|
}
|
|
|
|
#ifdef SPC386
|
|
/*
|
|
=============================== generic_ind ==================================
|
|
PURPOSE:
|
|
To simulate an IND using the appropriate INW routine.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
*/
|
|
LOCAL void generic_ind IFN2(io_addr, io_address, double_word *, value)
|
|
{
|
|
word low, high;
|
|
|
|
(*Ios_inw_function[Ios_in_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]]) (io_address, &low);
|
|
io_address += 2;
|
|
(*Ios_inw_function[Ios_in_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]]) (io_address, &high);
|
|
#ifdef LITTLEND
|
|
*((word *) value + 0) = low;
|
|
*((word *) value + 1) = high;
|
|
#endif /* LITTLEND */
|
|
|
|
#ifdef BIGEND
|
|
*((word *) value + 0) = high;
|
|
*((word *) value + 1) = low;
|
|
#endif /* BIGEND */
|
|
}
|
|
#endif /* SPC386 */
|
|
|
|
#ifdef SPC386
|
|
/*
|
|
=============================== generic_outd ==================================
|
|
PURPOSE:
|
|
To simulate an OUTD using the appropriate OUTW routine.
|
|
INPUT:
|
|
OUTPUT:
|
|
Notes: GLOBAL for JOKER.
|
|
==============================================================================
|
|
*/
|
|
LOCAL void generic_outd IFN2(io_addr, io_address, double_word, value)
|
|
{
|
|
word low, high;
|
|
|
|
low = value & 0xffff;
|
|
high = (value & 0xffff0000) >> 16;
|
|
|
|
(*Ios_outw_function[Ios_out_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]]) (io_address, low);
|
|
io_address += 2;
|
|
(*Ios_outw_function[Ios_out_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]]) (io_address, high);
|
|
}
|
|
#endif /* SPC386 */
|
|
|
|
/*
|
|
=============================== generic_insb ==================================
|
|
PURPOSE:
|
|
To simulate an INSB using the appropriate INB routine.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
*/
|
|
|
|
/* MS NT monitor uses these string routines {in,out}s{b,w} string io support */
|
|
#if defined(NTVDM) && defined(MONITOR)
|
|
#undef LOCAL
|
|
#define LOCAL
|
|
#endif /* NTVDM & MONITOR */
|
|
|
|
LOCAL void generic_insb IFN3(io_addr, io_address, half_word *, valarray,
|
|
word, count)
|
|
{
|
|
IOS_FUNC_INB func = Ios_inb_function[Ios_in_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]];
|
|
|
|
while (count--){
|
|
(*func) (io_address, valarray++);
|
|
}
|
|
}
|
|
|
|
/*
|
|
=============================== generic_outsb =================================
|
|
PURPOSE:
|
|
To simulate an OUTSB using the appropriate OUTB routine.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
*/
|
|
LOCAL void generic_outsb IFN3(io_addr, io_address, half_word *, valarray, word, count)
|
|
{
|
|
IOS_FUNC_OUTB func = Ios_outb_function[Ios_out_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]];
|
|
|
|
while (count--){
|
|
(*func) (io_address, *valarray++);
|
|
}
|
|
}
|
|
|
|
/*
|
|
=============================== generic_insw ==================================
|
|
PURPOSE:
|
|
To simulate an INSW using the appropriate INW routine.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
*/
|
|
LOCAL void generic_insw IFN3(io_addr, io_address, word *, valarray, word, count)
|
|
{
|
|
IOS_FUNC_INW func = Ios_inw_function[Ios_in_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]];
|
|
|
|
while (count--){
|
|
(*func) (io_address, valarray++);
|
|
}
|
|
}
|
|
|
|
/*
|
|
=============================== generic_outsw =================================
|
|
PURPOSE:
|
|
To simulate an OUTSW using the appropriate OUTW routine.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
*/
|
|
LOCAL void generic_outsw IFN3(io_addr, io_address, word *, valarray, word, count)
|
|
{
|
|
IOS_FUNC_OUTW func = Ios_outw_function[Ios_out_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]];
|
|
|
|
while (count--){
|
|
(*func) (io_address, *valarray++);
|
|
}
|
|
}
|
|
|
|
#ifdef SPC386
|
|
/*
|
|
=============================== generic_insd ==================================
|
|
PURPOSE:
|
|
To simulate an INSD using the appropriate IND routine.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
*/
|
|
LOCAL VOID generic_insd IFN3(io_addr, io_address, double_word *, valarray, word, count)
|
|
{
|
|
IOS_FUNC_IND func = Ios_ind_function[Ios_in_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]];
|
|
|
|
while (count--){
|
|
(*func) (io_address, valarray++);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef SPC386
|
|
/*
|
|
=============================== generic_outsd =================================
|
|
PURPOSE:
|
|
To simulate an OUTSD using the appropriate OUTD routine.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
*/
|
|
LOCAL VOID generic_outsd IFN3(io_addr, io_address, double_word *, valarray, word, count)
|
|
{
|
|
IOS_FUNC_OUTD func = Ios_outd_function[Ios_out_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]];
|
|
|
|
while (count--){
|
|
(*func) (io_address, *valarray++);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* ensure any more LOCAL routines remain LOCAL */
|
|
#if defined(NTVDM) && defined(MONITOR)
|
|
#undef LOCAL
|
|
#define LOCAL static
|
|
/*
|
|
* string byte handlers for monitor
|
|
*/
|
|
VOID insb IFN3(io_addr, io_address, half_word *, valarray, word, count)
|
|
{
|
|
(*Ios_insb_function[getIOInAdapter(io_address)])
|
|
(io_address, valarray, count);
|
|
}
|
|
|
|
VOID outsb IFN3(io_addr, io_address, half_word *, valarray,word, count)
|
|
{
|
|
(*Ios_outsb_function[getIOInAdapter(io_address)])
|
|
(io_address, valarray, count);
|
|
}
|
|
|
|
VOID insw IFN3(io_addr, io_address, word *, valarray, word, count)
|
|
{
|
|
(*Ios_insw_function[getIOInAdapter(io_address)])
|
|
(io_address, valarray, count);
|
|
}
|
|
|
|
VOID outsw IFN3(io_addr, io_address, word *, valarray, word, count)
|
|
{
|
|
(*Ios_outsw_function[getIOInAdapter(io_address)])
|
|
(io_address, valarray, count);
|
|
}
|
|
|
|
#endif /* NTVDM & MONITOR */
|
|
|
|
/*
|
|
*
|
|
* ============================================================================
|
|
* Global Subroutines
|
|
* ============================================================================
|
|
*
|
|
*/
|
|
|
|
/*(
|
|
=================================== inb ======================================
|
|
PURPOSE:
|
|
To perform an INB - i.e. call the appropriate SoftPC adapter's INB
|
|
IO routine. Note that this routine is not intended to be used by
|
|
the assembler CPU directly - it is intended that the assembler CPU
|
|
access the data tables above directly to discover which routine to call.
|
|
|
|
This also needs to be true of 386 CPU, or you'll get into a very
|
|
nasty virtualisation loop.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
GLOBAL void inb IFN2(io_addr, io_address, half_word *, value)
|
|
{
|
|
#ifdef VIRTUALISATION
|
|
IU32 value32;
|
|
#endif /* VIRTUALISATION */
|
|
|
|
#ifdef EGA_DUMP
|
|
if (io_address >= MDA_PORT_START && io_address <= CGA_PORT_END)
|
|
dump_inb(io_address);
|
|
#endif
|
|
|
|
#ifdef VIRTUALISATION
|
|
|
|
#ifdef SYNCH_TIMERS
|
|
value32 = 0;
|
|
#endif /* SYNCH_TIMERS */
|
|
|
|
if (IOVirtualised(io_address, &value32, BIOS_INB_OFFSET, (sizeof(IU8))))
|
|
{
|
|
*value = (IU8)value32;
|
|
}
|
|
else
|
|
#endif /* VIRTUALISATION */
|
|
{
|
|
(*Ios_inb_function
|
|
[Ios_in_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]])
|
|
(io_address, value);
|
|
}
|
|
}
|
|
|
|
/*(
|
|
================================== outb ======================================
|
|
PURPOSE:
|
|
To perform an OUTB - i.e. call the appropriate SoftPC adapter's OUTB
|
|
IO routine. Note that this routine is not intended to be used by
|
|
the assembler CPU directly - it is intended that the assembler CPU
|
|
access the data tables above directly to discover which routine to call.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
GLOBAL void outb IFN2(io_addr, io_address, half_word, value)
|
|
{
|
|
#ifdef VIRTUALISATION
|
|
IU32 value32;
|
|
#endif /* VIRTUALISATION */
|
|
|
|
#ifdef EGA_DUMP
|
|
if (io_address >= MDA_PORT_START && io_address <= CGA_PORT_END)
|
|
dump_outb(io_address, value);
|
|
#endif
|
|
|
|
sub_note_trace2( IOS_VERBOSE, "outb( %x, %x )", io_address, value );
|
|
|
|
#ifdef VIRTUALISATION
|
|
value32 = value;
|
|
|
|
if (IOVirtualised(io_address, &value32, BIOS_OUTB_OFFSET, (sizeof(IU8))))
|
|
return;
|
|
else
|
|
#endif /* VIRTUALISATION */
|
|
{
|
|
(*Ios_outb_function[Ios_out_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]])
|
|
(io_address, value);
|
|
}
|
|
}
|
|
|
|
/*(
|
|
=================================== inw ======================================
|
|
PURPOSE:
|
|
To perform an INW - i.e. call the appropriate SoftPC adapter's INW
|
|
IO routine. Note that this routine is not intended to be used by
|
|
the assembler CPU directly - it is intended that the assembler CPU
|
|
access the data tables above directly to discover which routine to call.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
GLOBAL void inw IFN2(io_addr, io_address, word *, value)
|
|
{
|
|
#ifdef VIRTUALISATION
|
|
IU32 value32;
|
|
#endif /* VIRTUALISATION */
|
|
|
|
#ifdef EGA_DUMP
|
|
if (io_address >= MDA_PORT_START && io_address <= CGA_PORT_END)
|
|
dump_inw(io_address);
|
|
#endif
|
|
|
|
#ifdef VIRTUALISATION
|
|
|
|
#ifdef SYNCH_TIMERS
|
|
value32 = 0;
|
|
#endif /* SYNCH_TIMERS */
|
|
|
|
if (IOVirtualised(io_address, &value32, BIOS_INW_OFFSET, (sizeof(IU16))))
|
|
{
|
|
*value = (IU16)value32;
|
|
}
|
|
else
|
|
#endif /* VIRTUALISATION */
|
|
{
|
|
(*Ios_inw_function[Ios_in_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]])
|
|
(io_address, value);
|
|
}
|
|
}
|
|
|
|
/*(
|
|
================================== outw ======================================
|
|
PURPOSE:
|
|
To perform an OUTW - i.e. call the appropriate SoftPC adapter's OUTW
|
|
IO routine. Note that this routine is not intended to be used by
|
|
the assembler CPU directly - it is intended that the assembler CPU
|
|
access the data tables above directly to discover which routine to call.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
GLOBAL void outw IFN2(io_addr, io_address, word, value)
|
|
{
|
|
#ifdef VIRTUALISATION
|
|
IU32 value32;
|
|
#endif /* VIRTUALISATION */
|
|
|
|
#ifdef EGA_DUMP
|
|
if (io_address >= EGA_AC_INDEX_DATA && io_address <= EGA_IPSTAT1_REG)
|
|
dump_outw(io_address, value);
|
|
#endif
|
|
|
|
sub_note_trace2( IOS_VERBOSE, "outw( %x, %x )", io_address, value );
|
|
|
|
#ifdef VIRTUALISATION
|
|
value32 = value;
|
|
|
|
if (IOVirtualised(io_address, &value32, BIOS_OUTW_OFFSET, (sizeof(IU16))))
|
|
return;
|
|
else
|
|
#endif /* VIRTUALISATION */
|
|
{
|
|
(*Ios_outw_function[Ios_out_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]])
|
|
(io_address, value);
|
|
|
|
}
|
|
}
|
|
|
|
#ifdef SPC386
|
|
/*(
|
|
=================================== ind ======================================
|
|
PURPOSE:
|
|
To perform an IND - i.e. call the appropriate SoftPC adapter's IND
|
|
IO routine. Note that this routine is not intended to be used by
|
|
the assembler CPU directly - it is intended that the assembler CPU
|
|
access the data tables above directly to discover which routine to call.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
GLOBAL void ind IFN2(io_addr, io_address, IU32 *, value)
|
|
{
|
|
IU16 temp;
|
|
|
|
#ifdef VIRTUALISATION
|
|
IU32 value32;
|
|
|
|
#ifdef SYNCH_TIMERS
|
|
value32 = 0;
|
|
#endif /* SYNCH_TIMERS */
|
|
|
|
if (IOVirtualised(io_address, &value32, BIOS_IND_OFFSET, (sizeof(IU32))))
|
|
{
|
|
*value = value32;
|
|
}
|
|
else
|
|
#endif /* VIRTUALISATION */
|
|
{
|
|
inw(io_address,&temp);
|
|
*value = (IU32)temp;
|
|
io_address +=2;
|
|
inw(io_address,&temp);
|
|
*value |= ((IU32)temp << 16);
|
|
}
|
|
}
|
|
|
|
/*(
|
|
================================== outd ======================================
|
|
PURPOSE:
|
|
To perform an OUTD - i.e. call the appropriate SoftPC adapter's OUTD
|
|
IO routine. Note that this routine is not intended to be used by
|
|
the assembler CPU directly - it is intended that the assembler CPU
|
|
access the data tables above directly to discover which routine to call.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
GLOBAL void outd IFN2(io_addr, io_address, IU32, value)
|
|
{
|
|
sub_note_trace2( IOS_VERBOSE, "outd( %x, %x )", io_address, value );
|
|
|
|
#ifdef VIRTUALISATION
|
|
if (IOVirtualised(io_address, &value, BIOS_OUTD_OFFSET, (sizeof(IU32))))
|
|
return;
|
|
else
|
|
#endif /* VIRTUALISATION */
|
|
{
|
|
word temp;
|
|
|
|
temp = value & 0xffff;
|
|
outw(io_address,temp);
|
|
io_address +=2;
|
|
temp = (value >> 16);
|
|
outw(io_address,temp);
|
|
}
|
|
}
|
|
|
|
#endif /* SPC386 */
|
|
/*(
|
|
============================== io_define_inb =================================
|
|
PURPOSE:
|
|
To declare the address of the INB IO routine for the given adapter.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
GLOBAL void
|
|
#ifdef ANSI
|
|
io_define_inb(half_word adapter,
|
|
void (*func) IPT2(io_addr, io_address, half_word *, value))
|
|
#else
|
|
io_define_inb(adapter, func)
|
|
half_word adapter;
|
|
void (*func) ();
|
|
#endif /* ANSI */
|
|
{
|
|
Ios_inb_function[adapter] = FAST_FUNC_ADDR(func);
|
|
Ios_inw_function[adapter] = FAST_FUNC_ADDR(generic_inw);
|
|
Ios_insb_function[adapter] = generic_insb;
|
|
Ios_insw_function[adapter] = generic_insw;
|
|
#ifdef SPC386
|
|
Ios_ind_function[adapter] = generic_ind;
|
|
Ios_insd_function[adapter] = generic_insd;
|
|
#endif /* SPC386 */
|
|
}
|
|
|
|
/*(
|
|
========================== io_define_in_routines =============================
|
|
PURPOSE:
|
|
To declare the address of the input IO routine for the given adapter.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
GLOBAL void io_define_in_routines IFN5(half_word, adapter,
|
|
IOS_FUNC_INB, inb_func,
|
|
IOS_FUNC_INW, inw_func,
|
|
IOS_FUNC_INSB, insb_func,
|
|
IOS_FUNC_INSW, insw_func)
|
|
{
|
|
/*
|
|
* Preset defaultable entries to default value.
|
|
*/
|
|
Ios_inw_function[adapter] = FAST_FUNC_ADDR(generic_inw);
|
|
Ios_insb_function[adapter] = generic_insb;
|
|
Ios_insw_function[adapter] = generic_insw;
|
|
#ifdef SPC386
|
|
Ios_ind_function[adapter] = generic_ind;
|
|
Ios_insd_function[adapter] = generic_insd;
|
|
#endif /* SPC386 */
|
|
|
|
/*
|
|
* Process args into table entries
|
|
*/
|
|
Ios_inb_function[adapter] = FAST_FUNC_ADDR(inb_func);
|
|
if (inw_func) Ios_inw_function[adapter] = FAST_FUNC_ADDR(inw_func);
|
|
if (insb_func) Ios_insb_function[adapter] = insb_func;
|
|
if (insw_func) Ios_insw_function[adapter] = insw_func;
|
|
}
|
|
|
|
/*(
|
|
============================= io_define_outb =================================
|
|
PURPOSE:
|
|
To declare the address of the OUTB IO routine for the given adapter.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
GLOBAL void io_define_outb IFN2(half_word, adapter, IOS_FUNC_OUTB, func)
|
|
{
|
|
Ios_outb_function[adapter] = FAST_FUNC_ADDR(func);
|
|
Ios_outw_function[adapter] = FAST_FUNC_ADDR(generic_outw);
|
|
Ios_outsb_function[adapter] = generic_outsb;
|
|
Ios_outsw_function[adapter] = generic_outsw;
|
|
#ifdef SPC386
|
|
Ios_outd_function[adapter] = generic_outd;
|
|
Ios_outsd_function[adapter] = generic_outsd;
|
|
#endif /* SPC386 */
|
|
}
|
|
|
|
/*(
|
|
========================= io_define_out_routines =============================
|
|
PURPOSE:
|
|
To declare the address of the output IO routine for the given adapter.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
|
|
GLOBAL VOID io_define_out_routines IFN5(half_word, adapter,
|
|
IOS_FUNC_OUTB, outb_func,
|
|
IOS_FUNC_OUTW, outw_func,
|
|
IOS_FUNC_OUTSB, outsb_func,
|
|
IOS_FUNC_OUTSW, outsw_func)
|
|
{
|
|
/*
|
|
* Preset defaultable entries to default value.
|
|
*/
|
|
Ios_outw_function[adapter] = FAST_FUNC_ADDR(generic_outw);
|
|
Ios_outsb_function[adapter] = generic_outsb;
|
|
Ios_outsw_function[adapter] = generic_outsw;
|
|
#ifdef SPC386
|
|
Ios_outd_function[adapter] = generic_outd;
|
|
Ios_outsd_function[adapter] = generic_outsd;
|
|
#endif /* SPC386 */
|
|
|
|
/*
|
|
* Process args into table entries
|
|
*/
|
|
Ios_outb_function[adapter] = FAST_FUNC_ADDR(outb_func);
|
|
if (outw_func) Ios_outw_function[adapter] = FAST_FUNC_ADDR(outw_func);
|
|
if (outsb_func) Ios_outsb_function[adapter] = outsb_func;
|
|
if (outsw_func) Ios_outsw_function[adapter] = outsw_func;
|
|
}
|
|
|
|
#ifdef SPC386
|
|
/*(
|
|
========================= io_define_outd_routine =============================
|
|
PURPOSE:
|
|
To declare the address of the output IO routine for the given adapter.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
GLOBAL VOID io_define_outd_routine IFN3(half_word, adapter,
|
|
IOS_FUNC_OUTD, outd_func, IOS_FUNC_OUTSD, outsd_func)
|
|
{
|
|
/*
|
|
* Preset defaultable entries to default value.
|
|
*/
|
|
Ios_outb_function[adapter] = io_empty_outb;
|
|
Ios_outw_function[adapter] = generic_outw;
|
|
Ios_outd_function[adapter] = generic_outd;
|
|
Ios_outsb_function[adapter] = generic_outsb;
|
|
Ios_outsw_function[adapter] = generic_outsw;
|
|
Ios_outsd_function[adapter] = generic_outsd;
|
|
|
|
/*
|
|
* Process args into table entries
|
|
*/
|
|
if (outd_func) Ios_outd_function[adapter] = outd_func;
|
|
if (outsd_func) Ios_outsd_function[adapter] = outsd_func;
|
|
}
|
|
#endif /* SPC386 */
|
|
|
|
#ifdef SPC386
|
|
/*(
|
|
========================= io_define_ind_routine =============================
|
|
PURPOSE:
|
|
To declare the address of the output IO routine for the given adapter.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
GLOBAL VOID io_define_ind_routine IFN3(half_word, adapter,
|
|
IOS_FUNC_IND, ind_func, IOS_FUNC_INSD, insd_func)
|
|
{
|
|
/*
|
|
* Preset defaultable entries to default value.
|
|
*/
|
|
Ios_inb_function[adapter] = io_empty_inb;
|
|
Ios_inw_function[adapter] = generic_inw;
|
|
Ios_ind_function[adapter] = generic_ind;
|
|
Ios_insb_function[adapter] = generic_insb;
|
|
Ios_insw_function[adapter] = generic_insw;
|
|
Ios_insd_function[adapter] = generic_insd;
|
|
|
|
/*
|
|
* Process args into table entries
|
|
*/
|
|
if (ind_func) Ios_ind_function[adapter] = ind_func;
|
|
if (insd_func) Ios_insd_function[adapter] = insd_func;
|
|
}
|
|
#endif /* SPC386 */
|
|
|
|
/*(
|
|
============================= io_connect_port ================================
|
|
PURPOSE:
|
|
To associate a SoftPC IO adapter with the given IO address.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
#ifdef NTVDM
|
|
GLOBAL BOOL io_connect_port IFN3(io_addr, io_address, half_word, adapter,
|
|
half_word, mode)
|
|
{
|
|
if (mode & IO_READ){
|
|
Ios_in_adapter_table[io_address & (PC_IO_MEM_SIZE-1)] = adapter;
|
|
}
|
|
if (mode & IO_WRITE){
|
|
Ios_out_adapter_table[io_address & (PC_IO_MEM_SIZE-1)] = adapter;
|
|
}
|
|
return TRUE;
|
|
}
|
|
#else
|
|
GLOBAL void io_connect_port IFN3(io_addr, io_address, half_word, adapter,
|
|
half_word, mode)
|
|
{
|
|
if (mode & IO_READ){
|
|
Ios_in_adapter_table[io_address & (PC_IO_MEM_SIZE-1)] = adapter;
|
|
}
|
|
if (mode & IO_WRITE){
|
|
Ios_out_adapter_table[io_address & (PC_IO_MEM_SIZE-1)] = adapter;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/*(
|
|
=========================== io_disconnect_port ===============================
|
|
PURPOSE:
|
|
To associate the empty adapter with the given IO address.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
#ifdef NTVDM
|
|
GLOBAL void io_disconnect_port IFN2(io_addr, io_address, half_word, adapter)
|
|
{
|
|
if (adapter != Ios_in_adapter_table[io_address & (PC_IO_MEM_SIZE-1)] &&
|
|
adapter != Ios_out_adapter_table[io_address & (PC_IO_MEM_SIZE-1)])
|
|
{
|
|
return;
|
|
}
|
|
|
|
Ios_in_adapter_table[io_address & (PC_IO_MEM_SIZE-1)] = EMPTY_ADAPTOR;
|
|
Ios_out_adapter_table[io_address & (PC_IO_MEM_SIZE-1)] = EMPTY_ADAPTOR;
|
|
}
|
|
#else
|
|
GLOBAL void io_disconnect_port IFN2(io_addr, io_address, half_word, adapter)
|
|
{
|
|
UNUSED(adapter);
|
|
Ios_in_adapter_table[io_address] = EMPTY_ADAPTOR;
|
|
Ios_out_adapter_table[io_address] = EMPTY_ADAPTOR;
|
|
}
|
|
#endif /* NTVDM */
|
|
|
|
|
|
/*(
|
|
=========================== get_inb_ptr ======================================
|
|
PURPOSE:
|
|
To return address of inb routine for the given port
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
GLOBAL IOS_FUNC_INB *get_inb_ptr IFN1(io_addr, io_address)
|
|
{
|
|
return(&Ios_inb_function[Ios_in_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]]);
|
|
}
|
|
|
|
/*(
|
|
=========================== get_outb_ptr =====================================
|
|
PURPOSE:
|
|
To return address of outb routine for the given port
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
GLOBAL IOS_FUNC_OUTB *get_outb_ptr IFN1(io_addr, io_address)
|
|
{
|
|
return(&Ios_outb_function[Ios_out_adapter_table[io_address & (PC_IO_MEM_SIZE-1)]]);
|
|
}
|
|
|
|
#ifdef SEGMENTATION
|
|
/*
|
|
* The following #include specifies the code segment into which this
|
|
* function will by placed by the MPW C compiler on the Mac II running
|
|
* MultiFinder.
|
|
*/
|
|
#include "SOFTPC_INIT.seg"
|
|
#endif
|
|
|
|
/*(
|
|
================================ io_init ===================================
|
|
PURPOSE:
|
|
To initialise the SoftPC IO subsystem.
|
|
INPUT:
|
|
OUTPUT:
|
|
==============================================================================
|
|
)*/
|
|
GLOBAL void io_init IFN0()
|
|
{
|
|
IU32 i; /* on some ports, PC_IO_MEM_SIZE == 0x10000, so this
|
|
must be a type with more than 16 bits */
|
|
|
|
/*
|
|
* Set up all IO address ports with the "empty" adapter
|
|
*/
|
|
io_define_inb (EMPTY_ADAPTOR, io_empty_inb);
|
|
io_define_outb(EMPTY_ADAPTOR, io_empty_outb);
|
|
|
|
#ifdef MAC68K
|
|
if (Ios_in_adapter_table == NULL) { /* First time around -- allocate */
|
|
Ios_in_adapter_table = host_malloc(PC_IO_MEM_SIZE);
|
|
Ios_out_adapter_table = host_malloc(PC_IO_MEM_SIZE);
|
|
}
|
|
#endif /* MAC68K */
|
|
|
|
#ifndef PROD
|
|
if (host_getenv("EMPTY_IO_VERBOSE") != NULL)
|
|
{
|
|
/* User does want empty I/O messages,
|
|
* so we must allocate bitmaps with one bit for every
|
|
* possible port number.
|
|
*/
|
|
ios_empty_in = (IU32 *)host_malloc((64*1024)/8);
|
|
ios_empty_out = (IU32 *)host_malloc((64*1024)/8);
|
|
memset((char *)ios_empty_in, 0, (64*1024)/8);
|
|
memset((char *)ios_empty_out, 0, (64*1024)/8);
|
|
}
|
|
#endif /* PROD */
|
|
|
|
for (i = 0; i < PC_IO_MEM_SIZE; i++){
|
|
Ios_in_adapter_table[i] = EMPTY_ADAPTOR;
|
|
Ios_out_adapter_table[i] = EMPTY_ADAPTOR;
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef NTVDM
|
|
GLOBAL char GetExtIoInAdapter (io_addr ioaddr)
|
|
{
|
|
#ifndef PROD
|
|
printf("GetExtIoInAdapter(%x) called\n",ioaddr);
|
|
#endif
|
|
return EMPTY_ADAPTOR;
|
|
}
|
|
|
|
GLOBAL char GetExtIoOutAdapter (io_addr ioaddr)
|
|
{
|
|
#ifndef PROD
|
|
printf("GetExtIoOutAdapter(%x) called\n",ioaddr);
|
|
#endif
|
|
return EMPTY_ADAPTOR;
|
|
}
|
|
#endif /* NTVDM */
|