📄 xt_wini.c
字号:
status = in_byte(WIN_DATA);
out_byte(WIN_DMA, 0);
if (!(status & 2)) /* Test "error" bit */
return(OK);
command[0] = WIN_SENSE;
command[1] = w_drive << 5;
if (com_out(NO_DMA_INT, command) != OK)
return(ERR);
/* Loop, extracting bytes from WIN */
for (i = 0; i < MAX_RESULTS; i++) {
if (hd_wait(WST_REQ) != OK)
return(ERR);
status = in_byte(WIN_DATA);
w_results[i] = status & BYTE;
}
if (hd_wait(WST_REQ) != OK) /* Missing from */
return (ERR); /* Original. 11-Apr-87 G.O. */
status = in_byte(WIN_DATA); /* Read "error" flag */
if (((status & 2) != 0) || (w_results[0] & 0x3F)) {
return(ERR);
} else
return(OK);
}
/*===========================================================================*
* win_out *
*===========================================================================*/
PRIVATE void win_out(val)
int val; /* write this byte to winchester disk controller */
{
/* Output a byte to the controller. This is not entirely trivial, since you
* can only write to it when it is listening, and it decides when to listen.
* If the controller refuses to listen, the WIN chip is given a hard reset.
*/
int r;
if (w_need_reset) return; /* if controller is not listening, return */
do {
r = in_byte(WIN_STATUS);
} while((r & (WST_REQ | WST_BUSY)) == WST_BUSY);
out_byte(WIN_DATA, val);
}
/*===========================================================================*
* w_reset *
*===========================================================================*/
PRIVATE int w_reset()
{
/* Issue a reset to the controller. This is done after any catastrophe,
* like the controller refusing to respond.
*/
int r, i, drive;
u8_t command[6];
message mess;
/* Strobe reset bit low. */
out_byte(WIN_STATUS, 0);
milli_delay(5); /* Wait for a while */
out_byte(WIN_SELECT, 0); /* Issue select pulse */
for (i = 0; i < MAX_WIN_RETRY; i++) {
r = in_byte(WIN_STATUS);
if (r & (WST_DRQ | WST_IRQ))
return(ERR);
if ((r & (WST_BUSY | WST_BUS | WST_REQ)) ==
(WST_BUSY | WST_BUS | WST_REQ))
break;
}
if (i == MAX_WIN_RETRY) {
printf("%s: reset failed, status = %x\n", w_name(), r);
return(ERR);
}
/* Reset succeeded. Tell WIN drive parameters. */
w_need_reset = FALSE;
for (drive = 0; drive < nr_drives; drive++) {
if (win_specify(drive) != OK)
return (ERR);
command[0] = WIN_RECALIBRATE;
command[1] = drive << 5;
command[5] = wini[drive].wn_ctlbyte;
if (com_out(INT, command) != OK)
return(ERR);
receive(HARDWARE, &mess);
if (win_results() != OK) {
/* No actual drive present? */
nr_drives = drive;
}
}
return(nr_drives > 0 ? OK : ERR);
}
/*==========================================================================*
* w_handler *
*==========================================================================*/
PRIVATE int w_handler(irq)
int irq;
{
/* Disk interrupt, send message to winchester task and reenable interrupts. */
int r, i;
out_byte(DMA_INIT, 0x07); /* Disable int from DMA */
for (i = 0; i < MAX_WIN_RETRY; ++i) {
r = in_byte(WIN_STATUS);
if (r & WST_IRQ)
break; /* Exit if end of int */
}
interrupt(WINCHESTER);
return 1;
}
/*============================================================================*
* win_specify *
*============================================================================*/
PRIVATE int win_specify(drive)
int drive;
{
struct wini *wn = &wini[drive];
u8_t command[6];
command[0] = WIN_SPECIFY; /* Specify some parameters */
command[1] = drive << 5; /* Drive number */
if (com_out(NO_DMA_INT, command) != OK) /* Output command block */
return(ERR);
/* No. of cylinders (high byte) */
win_out(wn->wn_cylinders >> 8);
/* No. of cylinders (low byte) */
win_out(wn->wn_cylinders);
/* No. of heads */
win_out(wn->wn_heads);
/* Start reduced write (high byte) */
win_out(wn->wn_reduced_wr >> 8);
/* Start reduced write (low byte) */
win_out(wn->wn_reduced_wr);
/* Start write precompensation (high byte) */
win_out(wn->wn_precomp >> 8);
/* Start write precompensation (low byte) */
win_out(wn->wn_precomp);
/* Ecc burst length */
win_out(wn->wn_max_ecc);
if (check_init() != OK) { /* See if controller accepted parameters */
w_need_reset = TRUE;
return(ERR);
} else
return(OK);
}
/*============================================================================*
* check_init *
*============================================================================*/
PRIVATE int check_init()
{
/* Routine to check if controller accepted the parameters */
int r, s;
if (hd_wait(WST_REQ | WST_INPUT) == OK) {
r = in_byte(WIN_DATA);
do {
s = in_byte(WIN_STATUS);
} while(s & WST_BUSY); /* Loop while still busy */
if (r & 2) /* Test error bit */
return(ERR);
else
return(OK);
} else
return (ERR); /* Missing from original: 11-Apr-87 G.O. */
}
/*============================================================================*
* read_ecc *
*============================================================================*/
PRIVATE int read_ecc()
{
/* Read the ecc burst-length and let the controller correct the data */
int r;
u8_t command[6];
command[0] = WIN_ECC_READ;
if (com_out(NO_DMA_INT, command) == OK && hd_wait(WST_REQ) == OK) {
r = in_byte(WIN_DATA);
if (hd_wait(WST_REQ) == OK) {
r = in_byte(WIN_DATA);
if (r & 1)
w_need_reset = TRUE;
}
}
return(ERR);
}
/*============================================================================*
* hd_wait *
*============================================================================*/
PRIVATE int hd_wait(bits)
int bits;
{
/* Wait until the controller is ready to receive a command or send status */
int r, i = 0;
do {
r = in_byte(WIN_STATUS) & bits;
} while ((i++ < MAX_WIN_RETRY) && r != bits); /* Wait for ALL bits */
if (i >= MAX_WIN_RETRY) {
w_need_reset = TRUE;
return(ERR);
} else
return(OK);
}
/*============================================================================*
* com_out *
*============================================================================*/
PRIVATE int com_out(mode, commandp)
int mode;
u8_t *commandp;
{
/* Output the command block to the winchester controller and return status */
int i, r;
out_byte(WIN_DMA, mode);
out_byte(WIN_SELECT, mode);
for (i = 0; i < MAX_WIN_RETRY; i++) {
r = in_byte(WIN_STATUS);
if (r & WST_BUSY)
break;
}
if (i == MAX_WIN_RETRY) {
w_need_reset = TRUE;
return(ERR);
}
for (i = 0; i < 6; i++) {
if (hd_wait(WST_REQ) != OK)
break; /* No data request pending */
r = in_byte(WIN_STATUS);
if ((r & (WST_BUSY | WST_BUS | WST_INPUT)) !=
(WST_BUSY | WST_BUS))
break;
out_byte(WIN_DATA, commandp[i]);
}
if (i != 6)
return(ERR);
else
return(OK);
}
/*==========================================================================*
* init_params *
*==========================================================================*/
PRIVATE void init_params()
{
/* This routine is called at startup to initialize the number of drives and
* the controller.
*/
u16_t parv[2];
unsigned int drive;
int dtype;
phys_bytes address, buf_phys;
char buf[16];
/* Get the number of drives from the bios */
buf_phys = vir2phys(buf);
phys_copy(0x475L, buf_phys, 1L);
nr_drives = buf[0] & 0xFF;
if (nr_drives > MAX_DRIVES) nr_drives = MAX_DRIVES;
/* Read the switches from the controller */
w_switches = in_byte(WIN_SELECT);
#if AUTO_BIOS
/* If no auto configuration or not enabled then go to the ROM. */
if (!(w_switches & AUTO_ENABLE)) {
#endif
for (drive = 0; drive < nr_drives; drive++) {
/* Calculate the drive type */
dtype = (w_switches >> (2 * drive)) & 03;
/* Copy the BIOS parameter vector */
phys_copy(WINI_0_PARM_VEC * 4L, vir2phys(parv), 4L);
/* Calculate the parameters' address and copy them to buf */
address = hclick_to_physb(parv[1]) + parv[0] + 16 * dtype;
phys_copy(address, buf_phys, 16L);
/* Copy the parameters to the structure of the drive. */
copy_param(buf, &wini[drive]);
}
#if AUTO_BIOS
}
#endif
}
/*============================================================================*
* w_do_open *
*============================================================================*/
PRIVATE int w_do_open(dp, m_ptr)
struct driver *dp;
message *m_ptr;
{
/* Device open: Initialize the controller and read the partition table. */
static int init_done = FALSE;
if (!init_done) { w_init(); init_done = TRUE; }
if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
if (w_wn->wn_open_ct++ == 0) {
/* Partition the disk. */
partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY);
}
return(OK);
}
/*============================================================================*
* w_do_close *
*============================================================================*/
PRIVATE int w_do_close(dp, m_ptr)
struct driver *dp;
message *m_ptr;
{
/* Device close: Release a device. */
if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
w_wn->wn_open_ct--;
return(OK);
}
/*==========================================================================*
* w_init *
*==========================================================================*/
PRIVATE void w_init()
{
/* Initialize the controller. */
int drive;
struct wini *wn;
#if AUTO_BIOS
message mess;
for (drive = 0; drive < nr_drives; drive++) {
/* Get the drive parameters from sector zero of the drive if the
* autoconfig mode of the controller has been selected.
*/
if (w_switches & AUTO_ENABLE) {
/* Set up some phony parameters so that we can read the
* first sector from the winchester. All drives will have
* one cylinder and one head but set up initially to the
* mini scribe drives from IBM.
*/
wn = &wini[drive];
wn->wn_cylinders = AUTO_CYLS;
wn->wn_heads = AUTO_HEADS;
wn->wn_reduced_wr = AUTO_RWC;
wn->wn_precomp = AUTO_WPC;
wn->wn_max_ecc = AUTO_ECC;
wn->wn_ctlbyte = AUTO_CTRL;
wn->wn_part[0].dv_size = SECTOR_SIZE;
}
}
/* Initialize controller to read parameters from the drives. */
if (nr_drives > 0 && w_reset() != OK) nr_drives = 0;
for (drive = 0; drive < nr_drives; drive++) {
if (w_switches & AUTO_ENABLE) {
/* read the first sector from the drive */
mess.DEVICE = drive * DEV_PER_DRIVE;
mess.POSITION = 0L;
mess.COUNT = SECTOR_SIZE;
mess.ADDRESS = (char *) tmp_buf;
mess.PROC_NR = WINCHESTER;
mess.m_type = DEV_READ;
if (do_rdwt(&w_dtab, &mess) != SECTOR_SIZE) {
printf("%s: can't read parameters\n", w_name());
nr_drives = drive;
break;
}
/* save the parameter tables for later use */
copy_param(&tmp_buf[AUTO_PARAM], &wini[drive]);
}
}
#endif
if (nr_drives > 0 && w_reset() != OK) nr_drives = 0;
/* Set the size of each disk. */
for (drive = 0; drive < nr_drives; drive++) {
(void) w_prepare(drive * DEV_PER_DRIVE);
wn = w_wn;
wn->wn_part[0].dv_size = ((unsigned long) wn->wn_cylinders *
wn->wn_heads * NR_SECTORS) << SECTOR_SHIFT;
printf("%s: %d cylinders, %d heads, %d sectors per track\n",
w_name(), wn->wn_cylinders, wn->wn_heads, NR_SECTORS);
}
}
/*==========================================================================*
* copy_param *
*==========================================================================*/
PRIVATE void copy_param(src, dest)
char *src;
struct wini *dest;
{
/* This routine copies the parameters from src to dest. */
dest->wn_cylinders = bp_cylinders(src);
dest->wn_heads = bp_heads(src);
dest->wn_reduced_wr = bp_reduced_wr(src);
dest->wn_precomp = bp_precomp(src);
dest->wn_max_ecc = bp_max_ecc(src);
dest->wn_ctlbyte = bp_ctlbyte(src);
}
/*============================================================================*
* w_geometry *
*============================================================================*/
PRIVATE void w_geometry(entry)
struct partition *entry;
{
entry->cylinders = w_wn->wn_cylinders;
entry->heads = w_wn->wn_heads;
entry->sectors = NR_SECTORS;
}
#endif /* ENABLE_XT_WINI */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -