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

📄 floppy.c

📁 minix3.1.1源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
 * If the controller refuses to listen, the FDC chip is given a hard reset. */  clock_t t0, t1;  int s, status;  if (need_reset) return;	/* if controller is not listening, return */  /* It may take several tries to get the FDC to accept a command.  */  getuptime(&t0);  do {  	if ( (s=getuptime(&t1))==OK && (t1-t0) > TIMEOUT_TICKS ) {  		if (OK!=s) printf("FLOPPY: warning, getuptime failed: %d\n", s); 		need_reset = TRUE;	/* hit it over the head */		return;	}  	if ((s=sys_inb(FDC_STATUS, &status)) != OK)  		panic("FLOPPY","Sys_inb in fdc_out() failed", s);  }  while ((status & (MASTER | DIRECTION)) != (MASTER | 0));     if ((s=sys_outb(FDC_DATA, val)) != OK)	panic("FLOPPY","Sys_outb in fdc_out() failed", s);}/*===========================================================================* *				recalibrate				     * *===========================================================================*/PRIVATE int recalibrate(){/* The floppy disk controller has no way of determining its absolute arm * position (cylinder).  Instead, it steps the arm a cylinder at a time and * keeps track of where it thinks it is (in software).  However, after a * SEEK, the hardware reads information from the diskette telling where the * arm actually is.  If the arm is in the wrong place, a recalibration is done, * which forces the arm to cylinder 0.  This way the controller can get back * into sync with reality. */  struct floppy *fp = f_fp;  int r;  u8_t cmd[2];  /* Issue the RECALIBRATE command and wait for the interrupt. */  cmd[0] = FDC_RECALIBRATE;	/* tell drive to recalibrate itself */  cmd[1] = f_drive;		/* specify drive */  if (fdc_command(cmd, 2) != OK) return(ERR_SEEK);  if (f_intr_wait() != OK) return(ERR_TIMEOUT);  /* Determine if the recalibration succeeded. */  fdc_out(FDC_SENSE);		/* issue SENSE command to request results */  r = fdc_results();		/* get results of the FDC_RECALIBRATE command*/  fp->fl_curcyl = NO_CYL;	/* force a SEEK next time */  fp->fl_sector = NO_SECTOR;  if (r != OK ||		/* controller would not respond */     (f_results[ST0] & ST0_BITS_SEEK) != SEEK_ST0 || f_results[ST_PCN] != 0) {	/* Recalibration failed.  FDC must be reset. */	need_reset = TRUE;	return(ERR_RECALIBRATE);  } else {	/* Recalibration succeeded. */	fp->fl_calibration = CALIBRATED;	fp->fl_curcyl = f_results[ST_PCN];	return(OK);  }}/*===========================================================================* *				f_reset					     * *===========================================================================*/PRIVATE void f_reset(){/* Issue a reset to the controller.  This is done after any catastrophe, * like the controller refusing to respond. */  pvb_pair_t byte_out[2];  int s,i;  message mess;  /* Disable interrupts and strobe reset bit low. */  need_reset = FALSE;  /* It is not clear why the next lock is needed.  Writing 0 to DOR causes   * interrupt, while the PC documentation says turning bit 8 off disables   * interrupts.  Without the lock:   *   1) the interrupt handler sets the floppy mask bit in the 8259.   *   2) writing ENABLE_INT to DOR causes the FDC to assert the interrupt   *      line again, but the mask stops the cpu being interrupted.   *   3) the sense interrupt clears the interrupt (not clear which one).   * and for some reason the reset does not work.   */  (void) fdc_command((u8_t *) 0, 0);   /* need only the timer */  motor_status = 0;  pv_set(byte_out[0], DOR, 0);			/* strobe reset bit low */  pv_set(byte_out[1], DOR, ENABLE_INT);		/* strobe it high again */  if ((s=sys_voutb(byte_out, 2)) != OK)  	panic("FLOPPY", "Sys_voutb in f_reset() failed", s);   /* A synchronous alarm timer was set in fdc_command. Expect a HARD_INT   * message to collect the reset interrupt, but be prepared to handle the    * SYN_ALARM message on a timeout.   */  do {  	receive(ANY, &mess);   	if (mess.m_type == SYN_ALARM) {   		f_expire_tmrs(NULL, NULL);	} else if(mess.m_type == DEV_PING) {		notify(mess.m_source);  	} else {			/* expect HARD_INT */  		f_busy = BSY_IDLE;  	}  } while (f_busy == BSY_IO);  /* The controller supports 4 drives and returns a result for each of them.   * Collect all the results now.  The old version only collected the first   * result.  This happens to work for 2 drives, but it doesn't work for 3   * or more drives, at least with only drives 0 and 2 actually connected   * (the controller generates an extra interrupt for the middle drive when   * drive 2 is accessed and the driver panics).   *   * It would be better to keep collecting results until there are no more.   * For this, fdc_results needs to return the number of results (instead   * of OK) when it succeeds.   */  for (i = 0; i < 4; i++) {	fdc_out(FDC_SENSE);	/* probe FDC to make it return status */	(void) fdc_results();	/* flush controller */  }  for (i = 0; i < NR_DRIVES; i++)	/* clear each drive */	floppy[i].fl_calibration = UNCALIBRATED;  /* The current timing parameters must be specified again. */  prev_dp = NULL;}/*===========================================================================* *				f_intr_wait				     * *===========================================================================*/PRIVATE int f_intr_wait(){/* Wait for an interrupt, but not forever.  The FDC may have all the time of * the world, but we humans do not. */  message mess;  /* We expect a HARD_INT message from the interrupt handler, but if there is   * a timeout, a SYN_ALARM notification is received instead. If a timeout    * occurs, report an error.   */  do {  	receive(ANY, &mess);   	if (mess.m_type == SYN_ALARM) {  		f_expire_tmrs(NULL, NULL);	} else if(mess.m_type == DEV_PING) {		notify(mess.m_source);  	} else {   		f_busy = BSY_IDLE;  	}  } while (f_busy == BSY_IO);  if (f_busy == BSY_WAKEN) {	/* No interrupt from the FDC, this means that there is probably no	 * floppy in the drive.  Get the FDC down to earth and return error.	 */	need_reset = TRUE;	return(ERR_TIMEOUT);  }  return(OK);}/*===========================================================================* *				f_timeout				     * *===========================================================================*/PRIVATE void f_timeout(tp)timer_t *tp;{/* This routine is called when a timer expires.  Usually to tell that a * motor has spun up, but also to forge an interrupt when it takes too long * for the FDC to interrupt (no floppy in the drive).  It sets a flag to tell * what has happened. */  if (f_busy == BSY_IO) {	f_busy = BSY_WAKEN;  }}/*===========================================================================* *				read_id					     * *===========================================================================*/PRIVATE int read_id(){/* Determine current cylinder and sector. */  struct floppy *fp = f_fp;  int result;  u8_t cmd[2];  /* Never attempt a read id if the drive is uncalibrated or motor is off. */  if (fp->fl_calibration == UNCALIBRATED) return(ERR_READ_ID);  if ((motor_status & (1 << f_drive)) == 0) return(ERR_READ_ID);  /* The command is issued by outputting 2 bytes to the controller chip. */  cmd[0] = FDC_READ_ID;		/* issue the read id command */  cmd[1] = (fp->fl_head << 2) | f_drive;  if (fdc_command(cmd, 2) != OK) return(ERR_READ_ID);  if (f_intr_wait() != OK) return(ERR_TIMEOUT);  /* Get controller status and check for errors. */  result = fdc_results();  if (result != OK) return(result);  if ((f_results[ST0] & ST0_BITS_TRANS) != TRANS_ST0) return(ERR_READ_ID);  if (f_results[ST1] | f_results[ST2]) return(ERR_READ_ID);  /* The next sector is next for I/O: */  fp->fl_sector = f_results[ST_SEC] - BASE_SECTOR + 1;  return(OK);}/*===========================================================================* *				f_do_open				     * *===========================================================================*/PRIVATE int f_do_open(dp, m_ptr)struct driver *dp;message *m_ptr;			/* pointer to open message */{/* Handle an open on a floppy.  Determine diskette type if need be. */  int dtype;  struct test_order *top;  /* Decode the message parameters. */  if (f_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);  dtype = f_device & DEV_TYPE_BITS;	/* get density from minor dev */  if (dtype >= MINOR_fd0p0) dtype = 0;  if (dtype != 0) {	/* All types except 0 indicate a specific drive/medium combination.*/	dtype = (dtype >> DEV_TYPE_SHIFT) - 1;	if (dtype >= NT) return(ENXIO);	f_fp->fl_density = dtype;	(void) f_prepare(f_device);	/* Recompute parameters. */	return(OK);  }  if (f_device & FORMAT_DEV_BIT) return(EIO);	/* Can't format /dev/fdN */  /* The device opened is /dev/fdN.  Experimentally determine drive/medium.   * First check fl_density.  If it is not NO_DENS, the drive has been used   * before and the value of fl_density tells what was found last time. Try   * that first.  If the motor is still running then assume nothing changed.   */  if (f_fp->fl_density != NO_DENS) {	if (motor_status & (1 << f_drive)) return(OK);	if (test_read(f_fp->fl_density) == OK) return(OK);  }  /* Either drive type is unknown or a different diskette is now present.   * Use test_order to try them one by one.   */  for (top = &test_order[0]; top < &test_order[NT-1]; top++) {	dtype = top->t_density;	/* Skip densities that have been proven to be impossible */	if (!(f_fp->fl_class & (1 << dtype))) continue;	if (test_read(dtype) == OK) {		/* The test succeeded, use this knowledge to limit the		 * drive class to match the density just read.		 */		f_fp->fl_class &= top->t_class;		return(OK);	}	/* Test failed, wrong density or did it time out? */	if (f_busy == BSY_WAKEN) break;  }  f_fp->fl_density = NO_DENS;  return(EIO);			/* nothing worked */}/*===========================================================================* *				test_read				     * *===========================================================================*/PRIVATE int test_read(density)int density;{/* Try to read the highest numbered sector on cylinder 2.  Not all floppy * types have as many sectors per track, and trying cylinder 2 finds the * ones that need double stepping. */  int device;  off_t position;  iovec_t iovec1;  int result;  f_fp->fl_density = density;  device = ((density + 1) << DEV_TYPE_SHIFT) + f_drive;  (void) f_prepare(device);  position = (off_t) f_dp->test << SECTOR_SHIFT;  iovec1.iov_addr = (vir_bytes) tmp_buf;  iovec1.iov_size = SECTOR_SIZE;  result = f_transfer(SELF, DEV_GATHER, position, &iovec1, 1);  if (iovec1.iov_size != 0) return(EIO);  partition(&f_dtab, f_drive, P_FLOPPY, 0);  return(OK);}/*===========================================================================* *				f_geometry				     * *===========================================================================*/PRIVATE void f_geometry(entry)struct partition *entry;{  entry->cylinders = f_dp->cyls;  entry->heads = NR_HEADS;  entry->sectors = f_sectors;}

⌨️ 快捷键说明

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