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

📄 esdi_wini.c

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


/*===========================================================================*
 *				w_schedule				     *
 *===========================================================================*/
PRIVATE int w_schedule(proc_nr, iop)
int proc_nr;			/* process doing the request */
struct iorequest_s *iop;	/* pointer to read or write request */
{
/* Gather I/O requests on consecutive blocks so they may be read/written
 * in one command if using a buffer.  Check and gather all the requests
 * and try to finish them as fast as possible if unbuffered.
 */
  int r, opcode;
  unsigned long pos;
  unsigned nbytes, count;
  unsigned long block;
  phys_bytes user_phys, dma_phys;

  /* This many bytes to read/write */
  nbytes = iop->io_nbytes;
  if ((nbytes & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);

  /* From/to this position on the device */
  pos = iop->io_position;
  if ((pos & SECTOR_MASK) != 0) return(iop->io_nbytes = EINVAL);

  /* To/from this user address */
  user_phys = numap(proc_nr, (vir_bytes) iop->io_buf, nbytes);
  if (user_phys == 0) return(iop->io_nbytes = EINVAL);

  /* Read or write? */
  opcode = iop->io_request & ~OPTIONAL_IO;

  /* Which block on disk and how close to EOF? */
  if (pos >= w_dv->dv_size) return(OK);		/* At EOF */
  if (pos + nbytes > w_dv->dv_size) nbytes = w_dv->dv_size - pos;
  block = (w_dv->dv_base + pos) >> SECTOR_SHIFT;

  if (USE_BUF && w_count > 0 && block != w_nextblock) {
	/* This new request can't be chained to the job being built */
	if ((r = w_finish()) != OK) return(r);
  }

  /* The next consecutive block */
  if (USE_BUF) w_nextblock = block + (nbytes >> SECTOR_SHIFT);

  /* While there are "unscheduled" bytes in the request: */
  do {
	count = nbytes;

	if (USE_BUF) {
		if (w_count == DMA_BUF_SIZE) {
			/* Can't transfer more than the buffer allows. */
			if ((r = w_finish()) != OK) return(r);
		}

		if (w_count + count > DMA_BUF_SIZE)
			count = DMA_BUF_SIZE - w_count;
	} else {
		if (w_tp == wtrans + NR_IOREQS) {
			/* All transfer slots in use. */
			if ((r = w_finish()) != OK) return(r);
		}
	}

	if (w_count == 0) {
		/* The first request in a row, initialize. */
		w_opcode = opcode;
		w_tp = wtrans;
	}

	if (USE_BUF) {
		dma_phys = tmp_phys + w_count;
	} else {
		/* Note: No 64K boundary problem, the better PS/2's have a
		 * working DMA chip.
		 */
		dma_phys = user_phys;
	}

	/* Store I/O parameters */
	w_tp->iop = iop;
	w_tp->block = block;
	w_tp->count = count;
	w_tp->phys = user_phys;
	w_tp->dma = dma_phys;

	/* Update counters */
	w_tp++;
	w_count += count;
	block += count >> SECTOR_SHIFT;
	user_phys += count;
	nbytes -= count;
  } while (nbytes > 0);

  return(OK);
}


/*===========================================================================*
 *				w_finish				     *
 *===========================================================================*/
PRIVATE int w_finish()
{
/*     carries out the I/O requests gathered in wtrans[]
 *
 *     fills the disk information structure for one block at a time or many
 *     in a row before calling 'w_transfer' to do the dirty work.  while
 *     unsuccessful operations are re-tried, this may be superfluous, since
 *     the controller does the same on its own.  turns on the fixed disk
 *     activity light, while busy.  computers need blinking lights, right?
 */

  struct trans *tp = wtrans, *tp2;
  unsigned count;
  int r, errors = 0, many = USE_BUF;

  if (w_count == 0) return(OK);	/* Spurious finish. */

  do {
	if (w_opcode == DEV_WRITE) {
		tp2 = tp;
		count = 0;
		do {
			if (USE_BUF || tp2->dma == tmp_phys) {
				phys_copy(tp2->phys, tp2->dma,
						(phys_bytes) tp2->count);
			}
			count += tp2->count;
			tp2++;
		} while (many && count < w_count);
	} else {
		count = many ? w_count : tp->count;
	}

	/* Turn on the disk activity light. */
	out_byte(SYS_PORTA, in_byte(SYS_PORTA) | LIGHT_ON);

	/* Perform the transfer. */
	r = w_transfer(tp, count);

	/* Turn off the disk activity light. */
	out_byte(SYS_PORTA, in_byte(SYS_PORTA) & ~LIGHT_ON);

	if (r != OK) {
		/* An error occurred, try again block by block unless */
		if (r == ERR_BAD_SECTOR || ++errors == MAX_ERRORS)
			return(tp->iop->io_nbytes = EIO);

		many = 0;
		continue;
	}
	errors = 0;

	w_count -= count;

	do {
		if (w_opcode == DEV_READ) {
			if (USE_BUF || tp->dma == tmp_phys) {
				phys_copy(tp->dma, tp->phys,
						(phys_bytes) tp->count);
			}
		}
		tp->iop->io_nbytes -= tp->count;
		count -= tp->count;
		tp++;
	} while (count > 0);
  } while (w_count > 0);

  return(OK);
}


/*===========================================================================*
 *				w_transfer				     *
 *===========================================================================*/
PRIVATE int w_transfer(tp, count)
struct trans *tp;		/* pointer to the transfer struct */
unsigned int count;		/* bytes to transfer */
{
/*     reads/writes a single block of data from/to the hard disk
 *
 *     the read/write operation performs the following steps:
 *       -- create the command block
 *       -- initialize the command reading by the controller
 *       -- write the command block to the controller, making sure the
 *            controller has digested the previous command word, before
 *            shoving the next down its throat.
 *       -- wait for an interrupt, which must return a 'data transfer ready'
 *            status.  abort the command if it doesn't.
 *       -- set up and start up the direct memory transfer
 *       -- wait for an interrupt, signalling the end of the transfer
 */
  int device;			/* device mask for the command register  */
  int ki;			/* -- scratch --                         */
  int status;			/* basic status register value           */

  device = w_drive << 5;
  command[0] = (w_opcode == DEV_WRITE ? 0x4602 : 0x4601) | device;
  command[1] = count >> SECTOR_SHIFT;
  command[2] = (int) (tp->block & 0xFFFF);
  command[3] = (int) (tp->block >> 16);

  w_att_write(device | ATT_CMD);

  for (ki = 0; ki < 4; ++ki) {
	out_word(CMD_REG, command[ki]);
	unlock();
	while (TRUE) {
		lock();
		status = in_byte(BST_REG);
		if (!(status & CMD_FUL)) break;
		unlock();
	}
  }
  unlock();

  w_interrupt(0);
  if (w_istat != (device | 0x0B)) {
	w_att_write(device | ATT_ABT);
	w_interrupt(0);
	return(ERR);
  }
  w_dma_setup(tp, count);

  w_interrupt(1);

  w_att_write(device | ATT_EOI);

  if ((w_istat & 0x0F) > 8) return(ERR);
  return(OK);
}



/*==========================================================================*
 *                            w_att_write                                   *
 *==========================================================================*/
PRIVATE int w_att_write(value)
register int value;
{
/*     writes a command to the esdi attention register
 *
 *     waits for the controller to finish its business before sending the
 *     command to the controller.  note that the interrupts must be off to read
 *     the basic status register and, if the controller is ready, must not be
 *     turned back on until the attention register command is sent.
 */
  int status;			/* basic status register value           */

  while (TRUE) {
	lock();
	status = in_byte(BST_REG);
	if (!(status & (INT_PND | BUSY))) break;
	unlock();
  }
  out_byte(ATT_REG, value);
  unlock();

  return(OK);
}



/*===========================================================================*
 *                          w_interrupt                                      *
 *===========================================================================*/
PRIVATE void w_interrupt(dma)
int dma;			/* i dma transfer is underway            */
{
/*     waits for an interrupt from the hard disk controller
 *
 *     enable interrupts on the hard disk and interrupt controllers (and dma if
 *     necessary).  wait for an interrupt.  when received, return the interrupt
 *     status register value.
 *
 *     an interrupt can be detected either from the basic status register or
 *     through a system interrupt handler.  the handler is used for all
 *     interrupts, due to the expected long times to process reads and writes
 *     and to avoid busy waits.
 */
  message dummy;		/* -- scratch --                         */

  out_byte(BCTL_REG, dma ? 0x03 : 0x01);

  receive(HARDWARE, &dummy);

  out_byte(BCTL_REG, 0);
  if (dma) out_byte(DMA_EXTCMD, 0x90 + dma_channel);
}



/*==========================================================================*
 *				w_handler				    *
 *==========================================================================*/
PRIVATE int w_handler(irq)
int irq;
{
/* Disk interrupt, send message to winchester task and reenable interrupts. */

  w_istat = in_byte(INT_REG);
  interrupt(WINCHESTER);
  return 1;
}



/*==========================================================================*
 *			w_dma_setup					    *
 *==========================================================================*/
PRIVATE void w_dma_setup(tp, count)
struct trans *tp;
unsigned int count;
{
/*     programs the dma controller to move data to and from the hard disk.
 *
 *     uses the extended mode operation of the ibm ps/2 interrupt controller
 *     chip, rather than the intel 8237 (pc/at) compatible mode.
 */

  lock();
  out_byte(DMA_EXTCMD, 0x90 + dma_channel);
  /* Disable access to dma channel 5     */
  out_byte(DMA_EXTCMD, 0x20 + dma_channel);
  /* Clear the address byte pointer      */
  out_byte(DMA_EXEC, (int)  tp->dma >>  0);	/* address bits 0..7   */
  out_byte(DMA_EXEC, (int)  tp->dma >>  8);	/* address bits 8..15  */
  out_byte(DMA_EXEC, (int) (tp->dma >> 16));	/* address bits 16..19 */
  out_byte(DMA_EXTCMD, 0x40 + dma_channel);
  /* Clear the count byte pointer        */
  out_byte(DMA_EXEC, (count - 1) >> 0);		/* count bits 0..7     */
  out_byte(DMA_EXEC, (count - 1) >> 8);		/* count bits 8..15    */
  out_byte(DMA_EXTCMD, 0x70 + dma_channel);
  /* Set the transfer mode               */
  out_byte(DMA_EXEC, w_opcode == DEV_WRITE ? 0x44 : 0x4C);
  out_byte(DMA_EXTCMD, 0xA0 + dma_channel);
  /* Enable access to dma channel 5      */
  unlock();
}


/*============================================================================*
 *				w_geometry				      *
 *============================================================================*/
PRIVATE void w_geometry(entry)
struct partition *entry;
{
  entry->cylinders = (w_wn->part[0].dv_size >> SECTOR_SHIFT) / (64 * 32);
  entry->heads = 64;
  entry->sectors = 32;
}
#endif /* ENABLE_ESDI_WINI */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -