Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1919 lines
45 KiB

#include "insignia.h"
#include "host_def.h"
/*
* INSIGNIA (SUB)MODULE SPECIFICATION -----------------------------
*
*
* THIS PROGRAM SOURCE FILE IS SUPPLIED IN CONFIDENCE TO THE CUSTOMER, THE
* CONTENTS OR DETAILS OF ITS OPERATION MUST NOT BE DISCLOSED TO ANY
* OTHER PARTIES WITHOUT THE EXPRESS AUTHORISATION FROM THE DIRECTORS OF
* INSIGNIA SOLUTIONS LTD.
*
*
* DOCUMENT :
*
* RELATED DOCS : WD2010-05 datasheet WD11C00C-22 (RMAC) eng.spec
* (Intel 82062 ... very similar to WD2010) IBM PC XT286 tech.ref
*
* DESIGNER : Jerry Kramskoy
*
* REVISION HISTORY : First version : 14-Sep-88.
*
* SUBMODULE NAME : fdisk
*
* SOURCE FILE NAME : fdisk.c
*
* PURPOSE : emulate fixed disk controller and sector buffer
* manager components of AT dual card.
*
* SccsID = @(#)fdisk.c 1.35 08/31/93 Copyright Insignia Solutions Ltd.
*
*
* [1.INTERMODULE INTERFACE SPECIFICATION]
*
* [1.0 INCLUDE FILE NEEDED TO ACCESS THIS INTERFACE FROM OTHER SUBMODULES]
*
* INCLUDE FILE : fdisk.gi
*
* [1.1 INTERMODULE EXPORTS]
*
* PROCEDURES() : fdisk_inb((io_addr)port, (unsigned char *)value)
* (uchar)fdisk_read_dir((io_addr)port, (unsigned char *)value) (void)
* fdisk_outb((io_addr)port, (unsigned char )value)
* fdisk_inw((io_addr)port, (unsigned short *)value) (void)
* fdisk_outw((io_addr)port,(unsigned short)value) (void)
* (void) fdisk_reset() (int) fdisk_physattach((int)driveno, (char
* *)name) (void) fdisk_physdetach((int)driveno) (void) fdisk_ioattach()
* (void) fdisk_iodetach()
*
* DATA : none
*
* -------------------------------------------------------------------------
* [1.2 DATATYPES FOR [1.1] (if not basic C types)]
*
* STRUCTURES/TYPEDEFS/ENUMS:
*
* -------------------------------------------------------------------------
* [1.3 INTERMODULE IMPORTS] (not o/s objects or standard libs)
*
* PROCEDURES() : none
*
* DATA : none
*
* -------------------------------------------------------------------------
*
* [1.4 DESCRIPTION OF INTERMODULE INTERFACE]
*
* [1.4.1 IMPORTED OBJECTS]
*
* FILES ACCESSED : disk image file(s) for C: (and D:)
*
* DEVICES ACCESSED : none
*
* SIGNALS CAUGHT : none
*
* SIGNALS ISSUED : none
*
*
* [1.4.2 EXPORTED OBJECTS]
* =========================================================================
* PROCEDURE : fdisk_inb((io_addr)port, (unsigned char *)value)
* fdisk_outb((io_addr)port, (unsigned char)value)
*
* PURPOSE : i/o space read (write) of a taskfile register these
* should be byte accesses.
*
* fdisk_inw((io_addr)port, (unsigned short *)value) fdisk_outw((io_addr)port,
* (unsigned short)value)
*
* PURPOSE : i/o space read (write) of next index into sector
* buffer. (for port 1f0). Not normal usage for accessing taskfile.
*
*
* PARAMETERS
*
* port : the i/o address to read. Taskfile addresses are (hex): (1f0)
* - data register (see fdisk_inw) 1f1 - error register 1f2
* - sector count register 1f3 - sector number register 1f4
* - cylinder low register 1f5 - cylinder high register 1f6
* - drive/head register 1f7 - status register
*
* value : (pointer to) byte (short) to receive the value contained in
* the specified register.
*
* GLOBALS : none.
*
* RETURNED VALUE : copy of returned value (inb, inw)
*
* DESCRIPTION : this procedure returns the contents of the specified
* register, having called any active state machine (which may update the
* status). Each disk command has a corresponding state machine, which gets
* initialised when the command is issued, and subsequently called as the
* command progresses. Only those commands involving data transfer between
* the host (cpu) and the adaptor can cause multiple calls to the state
* machine
*
* ERROR INDICATIONS : none
*
* ERROR RECOVERY : none
* =========================================================================
* PROCEDURE : (unsigned char) fdisk_read_dir((io_addr)port,
* (unsigned char *)value)
*
* PURPOSE : return the value of the 7 bits in the fixed disk
* register pertinent to the fixed disk. (cooperates with floppy)
*
* PARAMETERS : as per fdisk_inb()
*
* GLOBALS : the taskfile
*
* RETURNED VALUE : value of digital input register (at port 0x3f7)
*
* DESCRIPTION : obvious
*
* ERROR INDICATIONS : none
*
* ERROR RECOVERY : none
*
* =========================================================================
* PROCEDURE : fdisk_ioattach() fdisk_iodetach()
*
* PURPOSE : attach/detach the fixed disk components to the
* io-subsytem. plug/unplug the configured drives to the disk controller (if
* any). Patches drive parameter block table entries 0 and 1 in system ROM.
*
* PARAMETERS : none
*
* GLOBALS : the drive structure [fd, wiredup members]
*
* RETURNED VALUE : none
*
* DESCRIPTION : attaches/detaches to ios as usual. For the drive(s),
* the drive structure is used to see whether the disk image(s) are opened or
* non-existent. Based on existence, drive structure indicates plugged
* in/unplugged. On attach, disk parameter block table entries 1 and 2 (entry
* 1 for drive type 1 is used for the C drive (drive 0), and entry 2 for
* drive type 2 is used for the D drive (drive 1)) are edited to reflect the
* #.of cylinders available.
*
* ERROR INDICATIONS : none
*
* ERROR RECOVERY : none
* =========================================================================
* PROCEDURE : fdisk_physattach(driveno, name)
* fdisk_physdetach(driveno)
*
* PURPOSE : validate and attach host resource(s) for drive(s)
* /detach host resource(s).
*
* PARAMETERS : driveno - 0 (drive 0 (C:)) or 1
* (drive 1 (D:)) name - pointer to string for hard disk file
* name. If null string, then the indicated drive is taken to not exist.
*
* GLOBALS : the drive structure [fd, maxcyl members]
*
* RETURNED VALUE : none
*
* DESCRIPTION : for attaching, use host validation procedure to
* validate and open the specified drive image (if not the null string, else
* mark as no drive available). Use the #.of cylinders returned by the
* validation to set the max.cylinder number (= #.cyls - 1) into the drive
* structure for the drive.
*
* ERROR INDICATIONS : none
*
* ERROR RECOVERY : none
*
* =========================================================================
* PROCEDURE : fdisk_reset()
*
* PURPOSE : power up the disk subsystem.
*
* PARAMETERS : none
*
* GLOBALS : the taskfile
*
* RETURNED VALUE : none
*
* DESCRIPTION : sets registers etc. to their powered-up, pre-POST
* values.
*
* ERROR INDICATIONS : none
*
* ERROR RECOVERY : none
*
*
* =========================================================================
* [3.INTERMODULE INTERFACE DECLARATIONS]
* =========================================================================
*
* [3.1 INTERMODULE IMPORTS]
*/
IMPORT int soft_reset;
/* [3.1.1 #INCLUDES] */
#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_HDA.seg"
#endif
#include <stdio.h>
#include TypesH
#include StringH
#include "xt.h"
#include "trace.h"
#include CpuH
#include "error.h"
#include "config.h"
#include "ios.h"
#include "ica.h"
#include "dsktrace.h"
#include "debug.h"
#include "sas.h"
#include "quick_ev.h"
/* [3.1.2 DECLARATIONS] */
/* [3.2 INTERMODULE EXPORTS] */
#include "fdisk.h"
/*
* 5.MODULE INTERNALS : (not visible externally, global internally)]
*
* [5.1 LOCAL DECLARATIONS]
*/
/* [5.1.1 #DEFINES] */
/*
* task file ports (9 registers accessed via 7 ports)
*/
#define TFBASE 0x1f0
#define TFERROR 0x1f1
#define TFPCMP 0x1f1
#define TFSCOUNT 0x1f2
#define TFSNUM 0x1f3
#define TFCYLLO 0x1f4
#define TFCYLHI 0x1f5
#define TFDRVHD 0x1f6
#define TFSTATUS 0x1f7
#define TFCMD 0x1f7
/*
* task file indices ... the 7 ports map out to 9 registers (by using the
* read/write io signal) arbitrarily set the write precomp register and the
* command registers at indices 8 and 9
*/
#define WDERROR 1
#define WDSCOUNT 2
#define WDSNUM 3
#define WDCYLLO 4
#define WDCYLHI 5
#define WDDRVHD 6
#define WDSTAT 7
#define WDPCMP 8
#define WDCMD 9
/*
* wd2010 command register bits.
*/
#define WDCMD_I 0x08
#define WDCMD_M 0x04
#define WDCMD_L 0x02
#define WDCMD_T 0x01
/*
* command decoding constants, where bits 7-4 of command are non-unique
*/
#define DIAG_OR_PARMS 9
#define DIAG 0
#define PARMS 1
/*
* wd2010 status register bits
*/
#define WDSTATBUSY 0x80
#define WDSTATDRDY 0x40
#define WDSTATWFAULT 0x20
#define WDSTATSEEKCOMPLETE 0x10
#define WDSTATDRQ 0x08
#define WDSTATDC 0x04
#define WDSTATCIP 0x02
#define WDSTATERROR 0x01
/*
* wd2010 error register bits (bits 0,1,6,7 never get set for this emulation
* ... since these reflect bad ECC etc.)
*/
#define WDERRNOID 0x10
#define WDERRABORT 0x04
/*
* io signal
*/
#define IOREAD 0
#define IOWRITE ~IOREAD
/*
* interrupt line value
*/
#define IRQDEASSERT 0
#define IRQCLEAR 1
#define IRQASSERT ~IRQDEASSERT
/*
* state control for disk commands
*/
#define START 1 /* new command */
#define CONTINUE 2 /* command in progress */
#define BRDY 3 /* sector buffer ready */
#define BCR 4 /* clear sector buffer counter */
#define IDMISMATCH ~0 /* bad seek */
/* [5.1.2 TYPEDEF, STRUCTURE, ENUM DECLARATIONS] */
/*
* following describes the disk geometry for a drive, and the file descriptor
* for the disk image.
*/
typedef struct _drvinfo
{
long driveid;
long physattached;
long maxhead;
long maxcyl;
long maxsect;
long nsecspertrack;
long nbytespercyl;
long nbytespertrack;
long wiredup;
long curoffset;
} drvinfo_;
/* [5.1.3 PROCEDURE() DECLARATIONS] */
#ifdef ANSI
static void restore(int);
static void seek(int);
static void rsector(int);
static void wsector(int);
static void format(int);
static void rverify(int);
static void diagnose(int);
static void setparams(int);
static void bad(int);
static void irq(int);
static void rmac(unsigned short *, int);
static long dosearchid(void);
static void doseek(void);
static int disktobuffer(long);
static int buffertodisk(long);
#else
static void restore();
static void seek();
static void rsector();
static void wsector();
static void format();
static void rverify();
static void diagnose();
static void setparams();
static void bad();
static void irq();
static void rmac();
static long dosearchid();
static void doseek();
static int disktobuffer();
static int buffertodisk();
#endif /* ANSI */
/*
* -----------------------------------------------------------------------
* [5.2 LOCAL DEFINITIONS]
*
* [5.2.1 INTERNAL DATA DEFINITIONS
*/
/*
* dual card can support 2 drives max.
*/
static drvinfo_ drives[2];
/*
* pointer to the currently selected drive. (gets set up whenever the
* drive/head register in the taskfile gets written to)
*/
static drvinfo_ *pseldrv;
/*
* the fixed disk register (write only, 0x3f6)
*/
static unsigned char fixeddiskreg;
/*
* the digital input register .. reflects state of head and drive selected
*/
static unsigned char digipreg;
/*
* the wd2010 taskfile (element [0] is pad byte) ... 9 registers + dummy to
* allow direct table indexing
*/
LOCAL unsigned char taskfile[10];
/*
* command dispatch ... based on bits 7-4 of command register as index.
*/
LOCAL void (*dispatch[]) IPT1(int, state) =
{
bad,
restore,
rsector,
wsector,
rverify,
format,
bad,
seek,
bad,
bad, /* further decoded */
bad,
bad,
bad,
bad,
bad,
bad,
};
/*
* if a command is in progress, this points to the state machine for that
* command
*/
LOCAL void (*activecmd) IPT1(int, state);
/*
* sector buffer variables
*/
static unsigned char sectindx;
static unsigned short sectbuffer[256];
/* [5.2.2 INTERNAL PROCEDURE DEFINITIONS] */
/*
* ==========================================================================
* FUNCTION : dosearchid() PURPOSE : simulate
* searching for <cyl,hd,sec> id field. If out of range for configured
* geometry, return failure, else return appropriate file offset into disk
* image. N.B This assumes that ALL TRACKS have been FORMATTED WITH SECTOR
* ID's 1-#.sectors per track). EXTERNAL OBJECTS: drive info for
* selected drive; taskfile. RETURN VALUE : -1 if bad parameters
* for command else file offset (from byte 0) into hard disk image. INPUT
* PARAMS : RETURN PARAMS :
* ==========================================================================
*/
LOCAL long
dosearchid IFN0()
{
long head;
long cylinder;
long sector;
/*
* head ok? (heads numbered from 0 - maxhead)
*/
head = taskfile[WDDRVHD] & 0xf;
if (head > 7 && !(fixeddiskreg & 0x8))
return IDMISMATCH;
if (head > pseldrv->maxhead)
return IDMISMATCH;
/*
* sector ok? (assumes all tracks have been formatted with sector ids
* 1 - nsecspertrack which is DOS standard)
*/
sector = taskfile[WDSNUM];
if (sector > pseldrv->nsecspertrack || sector <= 0)
return IDMISMATCH;
/*
* cylinder ok? (we've imposed an artificial limit on the maximum
* cylinder number based upon the file size)
*/
cylinder = ((unsigned long) taskfile[WDCYLHI] << 8) +
(unsigned long) taskfile[WDCYLLO];
if (cylinder > pseldrv->maxcyl)
return IDMISMATCH;
return (cylinder * pseldrv->nbytespercyl + head *
pseldrv->nbytespertrack + (sector - 1L) * 512L);
}
/*
* ==========================================================================
* FUNCTION : updateposregs() PURPOSE : update the
* sector count and number registers. if this produces a track or cylinder
* transfer, then update the head/cylinder registers. This is a guestimate of
* what the WD1015 micro is doing when it handles these situations, and
* programs the WD2010. EXTERNAL OBJECTS: RETURN VALUE : INPUT PARAMS :
* RETURN PARAMS :
* ==========================================================================
*/
LOCAL void
updateposregs IFN0()
{
(taskfile[WDSCOUNT])--;
if (++taskfile[WDSNUM] > pseldrv->nsecspertrack)
{
int head;
int cylinder;
/*
* start at sector 1 of next track
*/
taskfile[WDSNUM] = 1;
head = taskfile[WDDRVHD] & 0xf;
if (++head > pseldrv->maxhead)
{
/*
* need to select next cylinder and use head 0.
*/
taskfile[WDDRVHD] &= 0xf0;
cylinder = ((unsigned int) taskfile[WDCYLHI] << 8) + taskfile[WDCYLLO];
taskfile[WDCYLLO] = (++cylinder) & 0xff;
taskfile[WDCYLHI] = cylinder >> 8;
} else
{
/*
* select next head to read next track
*/
taskfile[WDDRVHD] &= 0xf0;
taskfile[WDDRVHD] |= head;
if (head > 7)
fixeddiskreg |= 8;
}
}
}
/*
* ==========================================================================
* FUNCTION : doseek() PURPOSE : 'seek' to
* requested cylinder. if requested drive not wired up, then drive will not
* be ready. (and seek will be incomplete). If cylinder exceeds max. get
* drive ready and seek complete, but will get 'id not found' when the track
* gets accessed. EXTERNAL OBJECTS: RETURN VALUE : INPUT PARAMS :
* RETURN PARAMS :
* ==========================================================================
*/
LOCAL void
doseek IFN0()
{
/*
* the drive ready status will be set up when the drive/head register
* gets written to. here, just set the seek complete bit in the
* status register appropriately
*/
if (taskfile[WDSTAT] & WDSTATDRDY)
{
dt0(DHW | HWXINFO, 0, "\t\t+SC\n")
taskfile[WDSTAT] |= WDSTATSEEKCOMPLETE;
} else
{
dt0(DHW | HWXINFO, 0, "\t\t-SC\n")
taskfile[WDSTAT] &= ~WDSTATSEEKCOMPLETE;
}
}
/*
* ==========================================================================
* FUNCTION : restore() PURPOSE : EXTERNAL OBJECTS:
* RETURN VALUE : INPUT PARAMS : state - START or CONTINUE
* RETURN PARAMS :
* ==========================================================================
*/
LOCAL void
restore IFN1(int, state)
{
UNUSED(state);
dt0(DHW | HWXINFO, 0, "\tRESTORE cmd\n")
doseek();
if (!(taskfile[WDSTAT] & WDSTATDRDY))
{
taskfile[WDSTAT] |= WDSTATERROR;
taskfile[WDERROR] = WDERRABORT;
dt0(DHW | HWXINFO, 0, "\t\t+ERROR,err=abort\n")
}
dt0(DHW | HWXINFO, 0, "\t\t-BUSY -CIP\n")
taskfile[WDSTAT] &= ~WDSTATBUSY;
taskfile[WDSTAT] &= ~WDSTATCIP;
rmac((unsigned short *) 0, BCR);
irq(IRQASSERT);
}
/*
* ==========================================================================
* FUNCTION : seek() PURPOSE : emulate seek command.
* Just sets up appropriate status changes (error condition possibly)
* EXTERNAL OBJECTS: RETURN VALUE : INPUT PARAMS : state -
* START or CONTINUE RETURN PARAMS :
* ==========================================================================
*/
LOCAL void
seek IFN1(int, state)
{
UNUSED(state);
dt0(DHW | HWXINFO, 0, "\tSEEK cmd\n")
doseek();
/*
* if drive not ready, error
*/
if (!(taskfile[WDSTAT] & WDSTATDRDY))
{
dt0(DHW | HWXINFO, 0, "\t\t+ERROR,err=abort\n")
taskfile[WDSTAT] |= WDSTATERROR;
taskfile[WDERROR] = WDERRABORT;
}
/*
* deassert 'busy' and 'command in progress'; reset the sector buffer
* counter; issue interrupt
*/
dt0(DHW | HWXINFO, 0, "\t\t-BUSY -CIP\n")
taskfile[WDSTAT] &= ~WDSTATBUSY;
taskfile[WDSTAT] &= ~WDSTATCIP;
rmac((unsigned short *) 0, BCR);
irq(IRQASSERT);
}
/*
* ==========================================================================
* FUNCTION : rsector() PURPOSE : emulate read
* command. EXTERNAL OBJECTS: RETURN VALUE : INPUT PARAMS : state
* - START or CONTINUE or BRDY RETURN PARAMS :
* ==========================================================================
*/
LOCAL void
fdisk_pause IFN1(long, junk)
{
UNUSED(junk);
(*activecmd) (CONTINUE);
}
LOCAL void
rsector IFN1(int, state)
{
static int s;
long offset;
if (state == START)
{
dt0(DHW | HWXINFO, 0, "\tREAD cmd\n")
s = 0;
}
while (1)
switch (s)
{
case 0:
doseek();
if (!(taskfile[WDSTAT] & WDSTATDRDY))
{
dt0(DHW | HWXINFO, 0, "\t\t(drv not ready)set err=abort\n")
taskfile[WDERROR] |= WDERRABORT;
s = 3;
continue;
}
s = 1;
case 1:
if ((offset = dosearchid()) == IDMISMATCH)
{
dt0(DHW | HWXINFO, 0, "\t\tset err=abort,noid\n")
taskfile[WDERROR] = WDERRNOID | WDERRABORT;
s = 3;
continue;
}
s = 2;
case 2:
rmac((unsigned short *) 0, BCR);
/*
* disk controller transfers disk data to sector
* buffer
*/
if (!disktobuffer(offset))
{
dt0(DHW | HWXINFO, 0, "\t\tset err=abort,noid\n")
taskfile[WDERROR] = WDERRNOID | WDERRABORT;
s = 3;
continue;
}
rmac((unsigned short *) 0, BCR);
updateposregs();
/*
* at this point, tell the host to unload the sector
* buffer, and wait for BRDY signal from sector
* buffer when unloaded. (this will occur once host
* has done 256 inw's or equivalent)
*/
taskfile[WDSTAT] |= WDSTATDRQ;
taskfile[WDSTAT] &= ~WDSTATBUSY;
dt0(DHW | HWXINFO, 0, "\t\t+DRQ -BUSY\n")
if (taskfile[WDSCOUNT]
/* && (taskfile[WDCMD] & WDCMD_M) ??? M=1 case ??? */
)
{
/* more sectors to come */
irq(IRQASSERT);
s = 30;
} else
{
/* last sector done */
irq(IRQASSERT);
s = 31;
}
return;
case 3:
/*
* flag error in status register
*/
taskfile[WDSTAT] |= WDSTATERROR;
taskfile[WDSTAT] |= WDSTATDRQ;
taskfile[WDSTAT] &= ~WDSTATBUSY;
dt0(DHW | HWXINFO, 0, "\t\t+DRQ +ERROR -BUSY\n")
irq(IRQASSERT);
s = 31;
return;
case 30:
/*
* wait for buffer ready signal from sector buffer
*/
if (state == BRDY)
{
taskfile[WDSTAT] &= ~WDSTATDRQ;
taskfile[WDSTAT] |= WDSTATBUSY;
dt0(DHW | HWXINFO, 0, "\t\t-DRQ +BUSY\n")
irq(IRQDEASSERT);
/*
* Give CPU chance to run while we find the
* next disk sector. In particular the BIOS
* can read the disk status register before
* we raise the next interrupt. This is
* crucial as reading the disk status
* register deasserts the interrupt.
*/
add_q_event_i(fdisk_pause, HOST_FDISK_DELAY_1, 0);
s = 32;
}
return;
case 31:
if (state == BRDY)
{
taskfile[WDSTAT] &= ~WDSTATDRQ;
taskfile[WDSTAT] &= ~WDSTATCIP;
dt0(DHW | HWXINFO, 0, "\t\t-DRQ -CIP\n")
irq(IRQDEASSERT);
rmac((unsigned short *) 0, BCR);
}
return;
case 32:
s = 1;
continue;
}
}
/*
* ==========================================================================
* FUNCTION : wsector() PURPOSE : handle the
* 'write' command. EXTERNAL OBJECTS: RETURN VALUE : INPUT PARAMS :
* state - START or CONTINUE or BRDY RETURN PARAMS :
* ==========================================================================
*/
LOCAL void
wsector IFN1(int, state)
{
static int s;
long offset;
if (state == START)
{
dt0(DHW | HWXINFO, 0, "\tWRITE cmd\n")
s = 0;
}
while (1)
switch (s)
{
case 0:
/*
* tell host to fill sector buffer
*/
dt0(DHW | HWXINFO, 0, "\t\t+DRQ\n")
taskfile[WDSTAT] |= WDSTATDRQ;
s = 1;
return;
case 1:
/*
* wait for sector buffer to be filled by host (don't
* issue IRQ first time around)
*/
if (state == BRDY)
{
dt0(DHW | HWXINFO, 0, "\t\t-DRQ\n")
taskfile[WDSTAT] &= ~WDSTATDRQ;
s = 2;
continue;
}
return;
case 2:
/*
* check drive is ready, and can find sector to write
* to.
*/
doseek();
if (!(taskfile[WDSTAT] & WDSTATDRDY))
{
dt0(DHW | HWXINFO, 0, "\t\t(drv not ready)err=abort\n")
taskfile[WDERROR] |= WDERRABORT;
s = 10;
continue;
} else
{
if ((offset = dosearchid()) == IDMISMATCH)
{
dt0(DHW | HWXINFO, 0, "\t\terr=abort,noid\n")
taskfile[WDERROR] = WDERRNOID | WDERRABORT;
s = 10;
continue;
}
s = 3;
continue;
}
case 3:
rmac((unsigned short *) 0, BCR);
/*
* disk controller transfers sector buffer to disk
*/
if (!buffertodisk(offset))
{
/*
* any errors we report as missing ID
*/
dt0(DHW | HWXINFO, 0, "\t\terr=abort,noid\n")
taskfile[WDERROR] = WDERRNOID | WDERRABORT;
s = 10;
continue;
}
rmac((unsigned short *) 0, BCR);
updateposregs();
if (taskfile[WDSCOUNT])
{
/*
* more to go ... tell host to fill sector
* buffer again
*/
dt0(DHW | HWXINFO, 0, "\t\t+DRQ\n")
taskfile[WDSTAT] |= WDSTATDRQ;
irq(IRQASSERT);
s = 4;
return;
} else
/*
* all done
*/
s = 11;
continue;
case 4:
/*
* wait for sector buffer to be filled by host
*/
if (state == BRDY)
{
dt0(DHW | HWXINFO, 0, "\t\t-DRQ\n")
taskfile[WDSTAT] &= ~WDSTATDRQ;
/*
* prepare for next sector
*/
s = 2;
continue;
}
return;
case 10:
dt0(DHW | HWXINFO, 0, "\t\tset ERROR\n")
taskfile[WDSTAT] |= WDSTATERROR;
case 11:
dt0(DHW | HWXINFO, 0, "\t\t-BUSY -CIP\n")
taskfile[WDSTAT] &= ~WDSTATBUSY;
taskfile[WDSTAT] &= ~WDSTATCIP;
irq(IRQASSERT);
rmac((unsigned short *) 0, BCR);
return;
}
}
/*
* ==========================================================================
* FUNCTION : format() PURPOSE : handle the
* 'format' command. almost a 'dummy' command, but needs to make host write
* to sector buffer. EXTERNAL OBJECTS: RETURN VALUE : INPUT PARAMS :
* state - START or CONTINUE or BRDY RETURN PARAMS :
* ==========================================================================
*/
LOCAL void
format IFN1(int, state)
{
static int s;
if (state == START)
{
dt0(DHW | HWXINFO, 0, "\tFORMAT cmd\n")
s = 0;
}
while (1)
switch (s)
{
case 0:
/*
* initialise sector buffer tell application to write
* to sector buffer
*/
rmac((unsigned short *) 0, BCR);
dt0(DHW | HWXINFO, 0, "\t\t+DRQ\n")
taskfile[WDSTAT] |= WDSTATDRQ;
s = 1;
return;
case 1:
/*
* wait for sector buffer to fill
*/
if (state == BRDY)
{
/*
* no more data, thanks.
*/
doseek();
dt0(DHW | HWXINFO, 0, "\t\t-DRQ\n")
taskfile[WDSTAT] &= ~WDSTATDRQ;
if (!(taskfile[WDSTAT] & WDSTATDRDY))
{
/*
* formatting thin air!
*/
s = 2;
continue;
} else
{
int cylinder;
cylinder = ((unsigned int) taskfile[WDCYLHI] << 8)
+ taskfile[WDCYLLO];
if (cylinder > pseldrv->maxcyl)
/*
* formatting the spindle!
*/
s = 2;
else
s = 3;
continue;
}
}
return;
case 2:
dt0(DHW | HWXINFO, 0, "\t\t+ERROR,err=abort")
taskfile[WDERROR] |= WDERRABORT;
taskfile[WDSTAT] |= WDSTATERROR;
s = 3;
case 3:
irq(IRQASSERT);
dt0(DHW | HWXINFO, 0, "\t\t-BUSY -CIP")
taskfile[WDSTAT] &= ~WDSTATBUSY;
taskfile[WDSTAT] &= ~WDSTATCIP;
rmac((unsigned short *) 0, BCR);
return;
}
}
/*
* ==========================================================================
* FUNCTION : rverify() PURPOSE : handle the
* 'read verify' command. .. basically a dummy command. EXTERNAL OBJECTS:
* RETURN VALUE : INPUT PARAMS : state - START or CONTINUE
* RETURN PARAMS :
* ==========================================================================
*/
LOCAL void
rverify IFN1(int, state)
{
UNUSED(state);
/*
* if drive not ready, error
*/
dt0(DHW | HWXINFO, 0, "\tREAD VERIFY cmd\n")
doseek();
if (!(taskfile[WDSTAT] & WDSTATDRDY))
{
dt0(DHW | HWXINFO, 0, "\t\t+ERROR,err=abort\n")
taskfile[WDSTAT] |= WDSTATERROR;
taskfile[WDERROR] = WDERRABORT;
}
/*
* deassert 'busy' and 'command in progress'; reset the sector buffer
* counter; issue interrupt
*/
dt0(DHW | HWXINFO, 0, "\t\t-BUSY -CIP\n")
taskfile[WDSTAT] &= ~WDSTATBUSY;
taskfile[WDSTAT] &= ~WDSTATCIP;
rmac((unsigned short *) 0, BCR);
irq(IRQASSERT);
}
/*
* ==========================================================================
* FUNCTION : diagnose() PURPOSE : handle the
* 'diagnostics' command. EXTERNAL OBJECTS: RETURN VALUE : INPUT
* PARAMS : state - START or CONTINUE RETURN PARAMS :
* ==========================================================================
*/
LOCAL void
diagnose IFN1(int, state)
{
UNUSED(state);
dt0(DHW | HWXINFO, 0, "\tDIAGNOSTICS cmd\n")
/*
* flag diagnostics as successful
*/
dt0(DHW | HWXINFO, 0, "\t\terr=1\n")
taskfile[WDERROR] = 1;
/*
* deassert 'busy' and 'command in progress'; reset the sector buffer
* counter; issue interrupt
*/
dt0(DHW | HWXINFO, 0, "\t\t-BUSY -CIP\n")
taskfile[WDSTAT] &= ~WDSTATBUSY;
taskfile[WDSTAT] &= ~WDSTATCIP;
rmac((unsigned short *) 0, BCR);
irq(IRQASSERT);
}
/*
* ==========================================================================
* FUNCTION : setparams() PURPOSE : handle the
* 'set parameters' command. EXTERNAL OBJECTS: task file. drives. RETURN
* VALUE : INPUT PARAMS : state - START or CONTINUE
* RETURN PARAMS :
* ==========================================================================
*/
LOCAL void
setparams IFN1(int, state)
{
UNUSED(state);
dt0(DHW | HWXINFO, 0, "\tSET PARAMETERS cmd\n")
/*
* legal head values are 0 to (nheads-1)
*/
pseldrv->maxhead = taskfile[WDDRVHD] & 0xf;
/*
* legal sector ids are 1 to nsecspertrack
*/
pseldrv->nsecspertrack = taskfile[WDSCOUNT];
/*
* calculate some geometry constants ... the dual card is set up for
* 512 byte sectors.
*/
pseldrv->nbytespertrack = pseldrv->nsecspertrack * 512L;
pseldrv->nbytespercyl = pseldrv->nbytespertrack * (pseldrv->maxhead + 1L);
/*
* deassert 'busy' and 'command in progress'; reset the sector buffer
* counter; issue interrupt
*/
dt0(DHW | HWXINFO, 0, "\t\t-BUSY,-CIP,+SC\n")
taskfile[WDSTAT] &= ~WDSTATBUSY;
taskfile[WDSTAT] &= ~WDSTATCIP;
taskfile[WDSTAT] |= WDSTATSEEKCOMPLETE;
rmac((unsigned short *) 0, BCR);
irq(IRQASSERT);
}
/*
* ==========================================================================
* FUNCTION : bad() PURPOSE : handle unrecognised
* disk commands EXTERNAL OBJECTS: RETURN VALUE : INPUT PARAMS : state
* - START or CONTINUE RETURN PARAMS :
* ==========================================================================
*/
LOCAL void
bad IFN1(int, state)
{
UNUSED(state);
dt0(DHW | HWXINFO, 0, "\tBAD cmd\n")
taskfile[WDSTAT] |= WDSTATERROR;
taskfile[WDSTAT] &= ~WDSTATBUSY;
taskfile[WDSTAT] &= ~WDSTATCIP;
taskfile[WDERROR] = WDERRABORT;
dt0(DHW | HWXINFO, 0, "\t\t-BUSY -CIP +ERROR;err=abort\n")
rmac((unsigned short *) 0, BCR);
irq(IRQASSERT);
}
/*
* ==========================================================================
* FUNCTION : wd2010() PURPOSE : main
* procedure for the disk controller component of the dual card. This does
* NOT handle sector buffer accesses. EXTERNAL OBJECTS: taskfile,sectbuf.
* RETURN VALUE : INPUT PARAMS : taskindx - index into
* taskfile value - pointer to byte value io
* IOREAD or IOWRITE RETURN PARAMS : *value - set
* if IOWRITE
* ==========================================================================
*/
LOCAL void
wd2010 IFN3(int, taskindx, half_word *, value, int, io)
{
/*
* ignore any task file writes if command in progress (unless new
* command)
*/
if ((taskfile[WDSTAT] & WDSTATCIP) &&
io == IOWRITE && taskindx != WDCMD)
{
dt0(DHW | HWXINFO, 0, "\tcommand in progress .. write ignored\n")
return;
}
if (io == IOREAD)
{
/*
* deassert the interrupt request line.
*/
if (taskindx == WDSTAT)
irq(IRQDEASSERT);
/*
* if a command is in progress, then use this poll as an
* excuse to kick the controller again.
*/
if (taskfile[WDSTAT] & WDSTATCIP)
(*activecmd) (CONTINUE);
/*
* for the status register, return the WD2010 status. The
* real maccoy actually returns the RMAC's status which
* differs from the WD2010 in usage of bit 1. For the WD2010,
* this is the 'command in progress' status. For the RMAC,
* this is derived from the Index signal returned from the
* drive. Since this gives the appearance of being randomish,
* (unless being explicitly examined over a long period of
* time), just use the WD2010 value.
*/
*value = taskfile[taskindx];
return;
}
/*
* must be writing to task file and no command is in progress.
*/
taskfile[taskindx] = *value;
if (taskindx == WDCMD)
{
int cmd, drdy;
/*
* deassert interrupt request, clear error register, set
* 'command in progress' and busy. maintain same status of
* drive ready signal.
*/
irq(IRQDEASSERT);
taskfile[WDERROR] = 0;
drdy = taskfile[WDSTAT] & WDSTATDRDY;
if (drdy)
{
dt0(DHW | HWXINFO, 0, "\t\t+CIP -WF -SC -DRQ -DC -ERROR +BUSY +DRDY\n")
} else
{
dt0(DHW | HWXINFO, 0, "\t\t+CIP -WF -SC -DRQ -DC -ERROR +BUSY -DRDY\n")
}
taskfile[WDSTAT] = WDSTATCIP | WDSTATBUSY | drdy;
/*
* decode the command
*/
cmd = *value >> 4;
if (cmd == DIAG_OR_PARMS)
{
if ((*value & 0xf) == DIAG)
activecmd = diagnose;
else if ((*value & 0xf) == PARMS)
activecmd = setparams;
else
activecmd = bad;
} else
activecmd = dispatch[cmd];
/*
* and start the command off
*/
(*activecmd) (START);
} else if (taskindx == WDDRVHD)
{
/*
* digital input register reflects head select lines
*/
digipreg = (taskfile[WDDRVHD] & 0xf) >> 2;
if (taskfile[WDDRVHD] & 0x10)
{
/*
* drive 1 selected
*/
digipreg |= 2;
/*
* second drive selected. does it exist?
*/
if (!drives[1].wiredup)
{
/* no */
pseldrv = (drvinfo_ *) 0;
taskfile[WDSTAT] &= ~WDSTATDRDY;
dt0(DHW | HWXINFO, 0, "\t\t-DRDY\n")
} else
{
/* yes */
pseldrv = &drives[1];
taskfile[WDSTAT] |= WDSTATDRDY;
dt0(DHW | HWXINFO, 0, "\t\t+DRDY\n")
}
} else
{
/*
* first drive selected
*/
/*
* drive 1 selected
*/
digipreg |= 1;
if (!drives[0].wiredup)
{
/* no */
pseldrv = (drvinfo_ *) 0;
taskfile[WDSTAT] &= ~WDSTATDRDY;
dt0(DHW | HWXINFO, 0, "\t\t-DRDY\n")
} else
{
/* yes */
pseldrv = drives;
taskfile[WDSTAT] |= WDSTATDRDY;
dt0(DHW | HWXINFO, 0, "\t\t+DRDY\n")
}
}
}
}
/*
* ==========================================================================
* FUNCTION : irq() PURPOSE : assert/deassert the
* fixed disk interrupt line EXTERNAL OBJECTS: RETURN VALUE : INPUT
* PARAMS : line - IRQCLEAR,IRQASSERT or IRQDEASSERT
* RETURN PARAMS :
* ==========================================================================
*/
void disk_int_call_back IFN1(long, junk)
{
UNUSED(junk);
ica_hw_interrupt (1,6,1);
}
LOCAL void
irq IFN1(int, line)
{
static int intrq = IRQDEASSERT;
switch (line)
{
case IRQCLEAR:
dt0(DHW | INTRUPT, 0, "\t\t** -IRQ\n")
intrq = IRQDEASSERT;
break;
case IRQASSERT:
if (intrq != IRQASSERT)
{
dt0(DHW | INTRUPT, 0, "\t\t** +IRQ\n")
intrq = IRQASSERT;
/*
* check interrupts not masked out
*/
if (!(fixeddiskreg & 2))
add_q_event_i (disk_int_call_back, HOST_FDISK_DELAY_2, 0);
}
break;
case IRQDEASSERT:
if (intrq == IRQASSERT)
{
dt0(DHW | INTRUPT, 0, "\t\t** -IRQ\n")
intrq = IRQDEASSERT;
/* JOKER always wants to deassert the real ICA line */
#ifndef JOKER
if (!(fixeddiskreg & 2))
#endif
ica_clear_int(1, 6);
}
}
}
/*
* ==========================================================================
* FUNCTION : rmac() PURPOSE : emulate the buffer
* manager and controller (WD11C00C-22 (RMAC)) which looks after the sector
* buffer. EXTERNAL OBJECTS: RETURN VALUE : INPUT PARAMS : value
* - pointer to short to write/read with buffer. sig - READ,WRITE or
* BCR (BCR resets the buffer index .. simulates the BCR pulse) RETURN PARAMS
* :
* ==========================================================================
*/
LOCAL void
rmac IFN2(USHORT *, value, int, sig)
{
switch (sig)
{
case BCR:
dt0(DHW | HWXINFO, 0, "\t\tBCR raised to sector buffer\n")
sectindx = 0;
return;
case IOWRITE:
sectbuffer[sectindx] = *value;
break;
case IOREAD:
*value = sectbuffer[sectindx];
}
if (!++sectindx)
{
if (activecmd)
{
dt0(DHW | HWXINFO, 0, "\t\t++sector buffer raises BRDY\n")
(*activecmd) (BRDY);
}
}
}
/*
* ==========================================================================
* FUNCTION : disktobuffer() PURPOSE : read a sector
* from disk image into sector buffer EXTERNAL OBJECTS: drive structure
* RETURN VALUE : 0 - error reading file ~0 - ok.
* INPUT PARAMS : offset - file offset (from 0)
* ==========================================================================
*/
#define ONESECTOR 1
LOCAL int
disktobuffer IFN1(long, offset)
{
dt1(DHW | HWXINFO,0,
"\t\tdisk data(offset %lx(hex)) -> sector buffer\n", offset)
return host_fdisk_rd(pseldrv->driveid, offset, ONESECTOR, (char *) sectbuffer);
}
/*
* ==========================================================================
* FUNCTION : buffertodisk() PURPOSE : write the
* sector buffer to disk image EXTERNAL OBJECTS: drive structure
* RETURN VALUE : 0 - error reading file ~0 - ok.
* INPUT PARAMS : offset - file offset (from 0)
* ==========================================================================
*/
LOCAL int
buffertodisk IFN1(long, offset)
{
dt1(DHW | HWXINFO,0,
"\t\tsector buffer -> disk (offset %lx(hex))\n", offset)
return host_fdisk_wt(pseldrv->driveid, offset, ONESECTOR, (char *) sectbuffer);
}
/*
* 7.INTERMODULE INTERFACE IMPLEMENTATION :
*
* [7.1 INTERMODULE DATA DEFINITIONS]
*/
/*
* [7.2 INTERMODULE PROCEDURE DEFINITIONS]
*/
GLOBAL UTINY fdisk_read_dir IFN2(io_addr, port, UTINY *,value)
{
switch (port)
{
case 0x3f7:
*value = digipreg;
dt1(DHW | PORTIO, 0, "read of DIR returns %x(hex)\n", (unsigned) *value)
break;
default:
break;
}
return *value;
}
GLOBAL VOID fdisk_inb IFN2(io_addr, port, UTINY *,value)
{
dt0(DHW, 0, "(\n")
if (taskfile[WDSTAT] & WDSTATBUSY)
{
/* Controller is busy. Return status register contents. */
*value = taskfile[WDSTAT];
dt1(DHW | PORTIO, 0, "inb on port %x(hex) - controller busy\n", port)
/*
* deassert the interrupt request line.
*/
if ((port - TFBASE) == WDSTAT)
irq(IRQDEASSERT);
}
else
switch (port)
{
case TFBASE:
/*
* sector buffer must be accessed only in 16 bit quantities
*/
#ifndef PROD
printf("(fdisk_inb()) inb on sector buffer ignored!\n");
#endif
break;
default:
dt1(DHW | PORTIO, 0, "inb on port %x(hex)\n", port)
wd2010(port - TFBASE, value, IOREAD);
dt1(DHW | PORTIO, 0, "returns %x(hex)\n", (unsigned) *value)
}
dt0(DHW, 0, ")\n")
}
GLOBAL VOID fdisk_inw IFN2(io_addr, port, USHORT *, value)
{
#ifdef JOKER
/* This is the only way JOKER talks to disks, since
** Ade's fast disk bios is currently infeasible.
** Hence, speed is of interest here!
*/
if (port == TFBASE)
{
/* For speed, JOKER doesn't bother with calling rmac(IOREAD). */
*value = HostWordToIntelWord(sectbuffer[sectindx]);
if (!++sectindx) /* sectindx is a byte value -- wraparound? */
{
if (activecmd)
{
(*activecmd) (BRDY);
}
}
}
#else /* JOKER */
#ifdef BIGEND
unsigned short temp;
#endif
switch (port)
{
case TFBASE:
#ifdef LITTLEND
rmac(value, IOREAD);
#endif
#ifdef BIGEND
rmac(&temp, IOREAD);
*value = ((temp << 8) & 0xff00) | (temp >> 8);
#endif
#if 0
dt1(DHW | PORTIO, 0, "inw on sector buffer returns %x(hex)\n", *value)
#else
dt1(DHW | PORTIO, INW_TRACE_HNDL, "inw on sector buffer", *value)
#endif
break;
default:
/*
* task file registers must be accessed as byte quantities
*/
dt1(DHW | PORTIO, 0, "inw on port %x(hex) ignored!\n",
(unsigned) port)
break;
}
#endif /* JOKER */
}
GLOBAL VOID fdisk_outb IFN2(io_addr, port, UTINY, value)
{
dt0(DHW, 0, "(\n")
switch (port)
{
case TFBASE:
/*
* byte access to sector buffer is not a good idea
*/
#ifndef PROD
printf("(disk_outb()) outb to sector buffer ignored\n!");
#endif
break;
case TFPCMP:
dt2(DHW | PORTIO, 0, "outb to port %x(hex),val %x(hex)\n",
(unsigned) port, (unsigned) value)
wd2010(WDPCMP, &value, IOWRITE);
dt0(DHW | PORTIO, 0, "\n")
break;
case TFCMD:
dt2(DHW | PORTIO, 0, "outb to port %x(hex),val %x(hex)\n",
(unsigned) port, (unsigned) value)
wd2010(WDCMD, &value, IOWRITE);
dt0(DHW | PORTIO, 0, "\n")
break;
case DISKETTE_FDISK_REG:
/*
* Fixed disk register
*/
dt2(DHW | PORTIO, 0, "outb to port %x(hex),val %x(hex)\n",
(unsigned) port, (unsigned) value)
if ((fixeddiskreg & 0x4) && !(value & 0x4))
{
/* Turn reset off */
taskfile[WDSTAT] = WDSTATDRDY | WDSTATSEEKCOMPLETE;
/* Error register in diagnostic mode */
taskfile[WDERROR] = 0x01; /* No errors */
/* Reset rest of taskfile */
taskfile[WDSCOUNT] = taskfile[WDSNUM] = 0x01;
taskfile[WDCYLLO] = taskfile[WDCYLHI] = taskfile[WDDRVHD] = 0;
}
fixeddiskreg = value;
if (fixeddiskreg & 0x4)
{
/* Enable reset fixed disk function */
taskfile[WDSTAT] = WDSTATBUSY | WDSTATDC | WDSTATERROR;
}
break;
default:
dt2(DHW | PORTIO, 0, "outb to port %x(hex),val %x(hex)\n",
(unsigned) port, (unsigned) value)
wd2010(port - TFBASE, &value, IOWRITE);
dt0(DHW | PORTIO, 0, "\n")
}
dt0(DHW, 0, ")\n")
}
GLOBAL VOID fdisk_outw IFN2(io_addr, port, USHORT, value)
{
#ifdef BIGEND
unsigned short temp;
#endif
switch (port)
{
case TFBASE:
#if 0
dt1(DHW | PORTIO, 0, "outw to sector buffer, val %x(hex)\n",
(unsigned) value)
#else
dt1(DHW | PORTIO, OUTW_TRACE_HNDL, "outw to sector buffer",
(unsigned) value)
#endif
#ifdef LITTLEND
rmac(&value, IOWRITE);
#endif
#ifdef BIGEND
temp = ((value << 8) & 0xff00) | (value >> 8);
rmac(&temp, IOWRITE);
#endif
break;
default:
/*
* task file registers must be accessed as byte quantities
*/
dt1(DHW | PORTIO, 0, "outw to port %x(hex) ignored!\n",
(unsigned) port)
break;
}
}
GLOBAL VOID fdisk_ioattach IFN0()
{
unsigned short ncyls;
unsigned char nheads;
unsigned char nsects;
io_addr p;
/*
* attach to io subsystem
*/
io_define_in_routines (HDA_ADAPTOR, fdisk_inb, fdisk_inw, 0, 0);
io_define_out_routines(HDA_ADAPTOR, fdisk_outb, fdisk_outw, 0, 0);
/*
* attach taskfile
*/
for (p = DISK_PORT_START; p <= DISK_PORT_END; p++)
io_connect_port(p, HDA_ADAPTOR, IO_READ_WRITE);
/*
* attach Fixed disk register
*/
io_connect_port(DISKETTE_FDISK_REG, HDA_ADAPTOR, IO_WRITE);
if (drives[0].physattached)
{
/*
* indicate drive is wired up to controller
*/
drives[0].wiredup = ~0;
/*
* patch 'ROM' table for drive type 0 with appropriate number
* of cylinders
*/
ncyls = drives[0].maxcyl + 1;
nheads = drives[0].maxhead + 1;
nsects = drives[0].maxsect + 1;
#ifdef REAL_ROM
host_write_enable((DPB0 & (~0xfff)), (DPB0 & (~0xfff)) + 0x1000);
#endif
patch_rom(DPB0, (unsigned char) (ncyls & 0xff));
patch_rom(DPB0+1, (unsigned char) (ncyls >> 8));
patch_rom(DPB0+2, nheads);
patch_rom(DPB0+0xe, nsects);
#ifdef REAL_ROM
host_write_protect((DPB0 & (~0xfff)), (DPB0 & (~0xfff)) + 0x1000);
#endif
dt1(DHW | IOAD, 0, "drive 0 wiredup, total cyls %d\n",
(unsigned) ncyls)
}
if (drives[1].physattached)
{
/*
* indicate drive is wired up to controller
*/
drives[1].wiredup = ~0;
/*
* patch 'ROM' table for drive type 0 with appropriate number
* of cylinders
*/
ncyls = drives[1].maxcyl + 1;
nheads = drives[1].maxhead + 1;
nsects = drives[1].maxsect + 1;
#ifdef REAL_ROM
host_write_enable((DPB1 & (~0xfff)), (DPB1 & (~0xfff)) + 0x1000);
#endif
patch_rom(DPB1, ncyls & 0xff);
patch_rom(DPB1 + 1, (ncyls >> 8));
patch_rom(DPB1+2, nheads);
patch_rom(DPB1+0xe, nsects);
#ifdef REAL_ROM
host_write_protect((DPB1 & (~0xfff)), (DPB1 & (~0xfff)) + 0x1000);
#endif
dt1(DHW | IOAD, 0, "drive 1 wiredup, total cyls %d\n",
(unsigned) ncyls)
}
}
GLOBAL VOID fdisk_iodetach IFN0()
{
io_addr p;
/*
* detach from io subsystem
*/
for (p = DISK_PORT_START; p <= DISK_PORT_END; p++)
io_disconnect_port(p, HDA_ADAPTOR);
io_disconnect_port(DISKETTE_FDISK_REG, HDA_ADAPTOR);
if (drives[0].physattached)
{
/*
* indicate not wired up ... reset table in ROM to indicate
* 'bad drive type'
*/
drives[0].wiredup = 0;
#ifdef REAL_ROM
host_write_enable((DPB0 & (~0xfff)), (DPB0 & (~0xfff)) + 0x1000);
#endif
patch_rom(DPB0, 0);
patch_rom(DPB0 + 1, 0);
patch_rom(DPB0 + 2, 0);
patch_rom(DPB0 + 0xe, 0);
#ifdef REAL_ROM
host_write_protect((DPB0 & (~0xfff)), (DPB0 & (~0xfff)) + 0x1000);
#endif
dt0(DHW | IOAD, 0, "drive 0 unplugged\n")
}
if (drives[1].physattached)
{
/*
* indicate not wired up ... reset table in ROM to indicate
* 'bad drive type'
*/
drives[1].wiredup = 0;
#ifdef REAL_ROM
host_write_enable((DPB1 & (~0xfff)), (DPB1 & (~0xfff)) + 0x1000);
#endif
patch_rom(DPB1, 0);
patch_rom(DPB1 + 1, 0);
patch_rom(DPB1 + 2, 0);
patch_rom(DPB1 + 0xe, 0);
#ifdef REAL_ROM
host_write_protect((DPB1 & (~0xfff)), (DPB1 & (~0xfff)) + 0x1000);
#endif
dt0(DHW | IOAD, 0, "drive 1 unplugged\n")
}
}
GLOBAL VOID fdisk_physattach IFN1(int,driveno)
{
int invalid = 0;
int ncyls;
int nheads;
int nsects;
drives[driveno].driveid = driveno;
drives[driveno].physattached = 0;
if (!*((CHAR *) config_inquire(C_HARD_DISK1_NAME + driveno, NULL)))
return;
/*
* configuration specifies a disk image file ... validate it
*/
host_fdisk_get_params(driveno, &ncyls, &nheads, &nsects);
/*
* set maximum available cylinder value (this is
* artificial. The real controller on an AT does not
* have this knowledge ... it fails on ID matching if
* it seeks to a non-existent cylinder
*/
drives[driveno].nsecspertrack = nsects;
drives[driveno].nbytespertrack = nsects * 512L;
drives[driveno].nbytespercyl = drives[driveno].nbytespertrack * nheads;
drives[driveno].maxcyl = --ncyls;
drives[driveno].maxhead = --nheads;
drives[driveno].maxsect = --nsects;
drives[driveno].physattached = ~0;
fast_disk_bios_attach(driveno);
}
#ifdef macintosh
GLOBAL VOID fdisk_physdetach IFN1(int,driveno)
{
if (drives[driveno].physattached)
{
host_fdisk_close(driveno);
drives[driveno].physattached = 0;
fast_disk_bios_detach (driveno);
dt0(DHW|PAD, 0, "drive %d closed\n")
}
}
#endif /* macintosh */
GLOBAL VOID fdisk_reset IFN0()
{
taskfile[WDERROR] = 0;
taskfile[WDSCOUNT] = 0;
taskfile[WDSNUM] = 0;
taskfile[WDCYLLO] = 0;
taskfile[WDCYLHI] = 0;
taskfile[WDDRVHD] = 0;
/*
* show drive 1 selected ... head 0 selected
*/
digipreg = 1;
/*
* show drive is ready if available
*/
if (drives[0].wiredup)
{
taskfile[WDSTAT] = WDSTATDRDY | WDSTATSEEKCOMPLETE;
/*
* reposition file pointer for drive 0 at beginning of file
*/
host_fdisk_seek0(0);
} else
taskfile[WDSTAT] = 0;
if (drives[1].wiredup)
/*
* reposition file pointer for drive 1 at beginning of file
*/
host_fdisk_seek0(1);
/*
* initialise sector buffer
*/
rmac((unsigned short *) 0, BCR);
}
GLOBAL VOID hda_init IFN0()
{
fdisk_iodetach();
fast_disk_bios_detach(0);
fast_disk_bios_detach(1);
fdisk_physattach(0);
fdisk_physattach(1);
fdisk_ioattach();
fdisk_reset();
}