⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xt_wini.c

📁 MINIX2.0操作系统源码 MINIX2.0操作系统源码
💻 C
📖 第 1 页 / 共 2 页
字号:

  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 + -