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

📄 floppy.c

📁 minix3.1.1源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
 * opcode.  This routine sets up the DMA chip.  Note that the chip is not * capable of doing a DMA across a 64K boundary (e.g., you can't read a * 512-byte block starting at physical address 65520). * * Warning! Also note that it's not possible to do DMA above 16 MB because  * the ISA bus uses 24-bit addresses. Addresses above 16 MB therefore will  * be interpreted modulo 16 MB, dangerously overwriting arbitrary memory.  * A check here denies the I/O if the address is out of range.  */  pvb_pair_t byte_out[9];  int s;  /* First check the DMA memory address not to exceed maximum. */  if (tmp_phys != (tmp_phys & DMA_ADDR_MASK)) {	report("FLOPPY", "DMA denied because address out of range", NO_NUM);	return(EIO);  }  /* Set up the DMA registers.  (The comment on the reset is a bit strong,   * it probably only resets the floppy channel.)   */  pv_set(byte_out[0], DMA_INIT, DMA_RESET_VAL);	/* reset the dma controller */  pv_set(byte_out[1], DMA_FLIPFLOP, 0);		/* write anything to reset it */  pv_set(byte_out[2], DMA_MODE, opcode == DEV_SCATTER ? DMA_WRITE : DMA_READ);  pv_set(byte_out[3], DMA_ADDR, (unsigned) tmp_phys >>  0);  pv_set(byte_out[4], DMA_ADDR, (unsigned) tmp_phys >>  8);  pv_set(byte_out[5], DMA_TOP, (unsigned) (tmp_phys >> 16));  pv_set(byte_out[6], DMA_COUNT, (((SECTOR_SIZE - 1) >> 0) & 0xff));  pv_set(byte_out[7], DMA_COUNT, (SECTOR_SIZE - 1) >> 8);  pv_set(byte_out[8], DMA_INIT, 2);		/* some sort of enable */  if ((s=sys_voutb(byte_out, 9)) != OK)  	panic("FLOPPY","Sys_voutb in dma_setup() failed", s);  return(OK);}/*===========================================================================* *				start_motor				     * *===========================================================================*/PRIVATE void start_motor(){/* Control of the floppy disk motors is a big pain.  If a motor is off, you * have to turn it on first, which takes 1/2 second.  You can't leave it on * all the time, since that would wear out the diskette.  However, if you turn * the motor off after each operation, the system performance will be awful. * The compromise used here is to leave it on for a few seconds after each * operation.  If a new operation is started in that interval, it need not be * turned on again.  If no new operation is started, a timer goes off and the * motor is turned off.  I/O port DOR has bits to control each of 4 drives. */  int s, motor_bit, running;  message mess;  motor_bit = 1 << f_drive;		/* bit mask for this drive */  running = motor_status & motor_bit;	/* nonzero if this motor is running */  motor_status |= motor_bit;		/* want this drive running too */  if ((s=sys_outb(DOR,  		(motor_status << MOTOR_SHIFT) | ENABLE_INT | f_drive)) != OK)	panic("FLOPPY","Sys_outb in start_motor() failed", s);  /* If the motor was already running, we don't have to wait for it. */  if (running) return;			/* motor was already running */  /* Set an alarm timer to force a timeout if the hardware does not interrupt   * in time. Expect HARD_INT message, but check for SYN_ALARM timeout.   */   f_set_timer(&f_tmr_timeout, f_dp->start, f_timeout);  f_busy = BSY_IO;  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);  f_fp->fl_sector = NO_SECTOR;}/*===========================================================================* *				stop_motor				     * *===========================================================================*/PRIVATE void stop_motor(tp)timer_t *tp;{/* This routine is called from an alarm timer after several seconds have * elapsed with no floppy disk activity.  It turns the drive motor off. */  int s;  motor_status &= ~(1 << tmr_arg(tp)->ta_int);  if ((s=sys_outb(DOR, (motor_status << MOTOR_SHIFT) | ENABLE_INT)) != OK)	panic("FLOPPY","Sys_outb in stop_motor() failed", s);}/*===========================================================================* *				floppy_stop				     * *===========================================================================*/PRIVATE void floppy_stop(struct driver *dp, message *m_ptr){/* Stop all activity and cleanly exit with the system. */  int s;  sigset_t sigset = m_ptr->NOTIFY_ARG;  if (sigismember(&sigset, SIGTERM) || sigismember(&sigset, SIGKSTOP)) {      if ((s=sys_outb(DOR, ENABLE_INT)) != OK)		panic("FLOPPY","Sys_outb in floppy_stop() failed", s);      exit(0);	  }}/*===========================================================================* *				seek					     * *===========================================================================*/PRIVATE int seek(){/* Issue a SEEK command on the indicated drive unless the arm is already * positioned on the correct cylinder. */  struct floppy *fp = f_fp;  int r;  message mess;  u8_t cmd[3];  /* Are we already on the correct cylinder? */  if (fp->fl_calibration == UNCALIBRATED)	if (recalibrate() != OK) return(ERR_SEEK);  if (fp->fl_curcyl == fp->fl_hardcyl) return(OK);  /* No.  Wrong cylinder.  Issue a SEEK and wait for interrupt. */  cmd[0] = FDC_SEEK;  cmd[1] = (fp->fl_head << 2) | f_drive;  cmd[2] = fp->fl_hardcyl;  if (fdc_command(cmd, 3) != OK) return(ERR_SEEK);  if (f_intr_wait() != OK) return(ERR_TIMEOUT);  /* Interrupt has been received.  Check drive status. */  fdc_out(FDC_SENSE);		/* probe FDC to make it return status */  r = fdc_results();		/* get controller status bytes */  if (r != OK || (f_results[ST0] & ST0_BITS_SEEK) != SEEK_ST0				|| f_results[ST1] != fp->fl_hardcyl) {	/* seek failed, may need a recalibrate */	return(ERR_SEEK);  }  /* Give head time to settle on a format, no retrying here! */  if (f_device & FORMAT_DEV_BIT) {	/* Set a synchronous alarm to force a timeout if the hardware does	 * not interrupt. Expect HARD_INT, but check for SYN_ALARM timeout. 	 */  	f_set_timer(&f_tmr_timeout, HZ/30, f_timeout);	f_busy = BSY_IO;  	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);  }  fp->fl_curcyl = fp->fl_hardcyl;  fp->fl_sector = NO_SECTOR;  return(OK);}/*===========================================================================* *				fdc_transfer				     * *===========================================================================*/PRIVATE int fdc_transfer(opcode)int opcode;			/* DEV_GATHER or DEV_SCATTER */{/* The drive is now on the proper cylinder.  Read, write or format 1 block. */  struct floppy *fp = f_fp;  int r, s;  u8_t cmd[9];  /* Never attempt a transfer if the drive is uncalibrated or motor is off. */  if (fp->fl_calibration == UNCALIBRATED) return(ERR_TRANSFER);  if ((motor_status & (1 << f_drive)) == 0) return(ERR_TRANSFER);  /* The command is issued by outputting several bytes to the controller chip.   */  if (f_device & FORMAT_DEV_BIT) {	cmd[0] = FDC_FORMAT;	cmd[1] = (fp->fl_head << 2) | f_drive;	cmd[2] = fmt_param.sector_size_code;	cmd[3] = fmt_param.sectors_per_cylinder;	cmd[4] = fmt_param.gap_length_for_format;	cmd[5] = fmt_param.fill_byte_for_format;	if (fdc_command(cmd, 6) != OK) return(ERR_TRANSFER);  } else {	cmd[0] = opcode == DEV_SCATTER ? FDC_WRITE : FDC_READ;	cmd[1] = (fp->fl_head << 2) | f_drive;	cmd[2] = fp->fl_cylinder;	cmd[3] = fp->fl_head;	cmd[4] = BASE_SECTOR + fp->fl_sector;	cmd[5] = SECTOR_SIZE_CODE;	cmd[6] = f_sectors;	cmd[7] = f_dp->gap;	/* sector gap */	cmd[8] = DTL;		/* data length */	if (fdc_command(cmd, 9) != OK) return(ERR_TRANSFER);  }  /* Block, waiting for disk interrupt. */  if (f_intr_wait() != OK) {	printf("%s: disk interrupt timed out.\n", f_name());  	return(ERR_TIMEOUT);  }  /* Get controller status and check for errors. */  r = fdc_results();  if (r != OK) return(r);  if (f_results[ST1] & WRITE_PROTECT) {	printf("%s: diskette is write protected.\n", f_name());	return(ERR_WR_PROTECT);  }  if ((f_results[ST0] & ST0_BITS_TRANS) != TRANS_ST0) return(ERR_TRANSFER);  if (f_results[ST1] | f_results[ST2]) return(ERR_TRANSFER);  if (f_device & FORMAT_DEV_BIT) return(OK);  /* Compare actual numbers of sectors transferred with expected number. */  s =  (f_results[ST_CYL] - fp->fl_cylinder) * NR_HEADS * f_sectors;  s += (f_results[ST_HEAD] - fp->fl_head) * f_sectors;  s += (f_results[ST_SEC] - BASE_SECTOR - fp->fl_sector);  if (s != 1) return(ERR_TRANSFER);  /* This sector is next for I/O: */  fp->fl_sector = f_results[ST_SEC] - BASE_SECTOR;#if 0  if (processor < 386) fp->fl_sector++;		/* Old CPU can't keep up. */#endif  return(OK);}/*===========================================================================* *				fdc_results				     * *===========================================================================*/PRIVATE int fdc_results(){/* Extract results from the controller after an operation, then allow floppy * interrupts again. */  int s, result_nr, status;  clock_t t0,t1;  /* Extract bytes from FDC until it says it has no more.  The loop is   * really an outer loop on result_nr and an inner loop on status.    * A timeout flag alarm is set.   */  result_nr = 0;  getuptime(&t0);  do {	/* Reading one byte is almost a mirror of fdc_out() - the DIRECTION	 * bit must be set instead of clear, but the CTL_BUSY bit destroys	 * the perfection of the mirror.	 */	if ((s=sys_inb(FDC_STATUS, &status)) != OK)		panic("FLOPPY","Sys_inb in fdc_results() failed", s);	status &= (MASTER | DIRECTION | CTL_BUSY);	if (status == (MASTER | DIRECTION | CTL_BUSY)) {		if (result_nr >= MAX_RESULTS) break;	/* too many results */		if ((s=sys_inb(FDC_DATA, &f_results[result_nr])) != OK)		   panic("FLOPPY","Sys_inb in fdc_results() failed", s);		result_nr ++;		continue;	}	if (status == MASTER) {			/* all read */		if ((s=sys_irqenable(&irq_hook_id)) != OK)			panic("FLOPPY", "Couldn't enable IRQs", s);		return(OK);			/* only good exit */	}  } while ( (s=getuptime(&t1))==OK && (t1-t0) < TIMEOUT_TICKS );  if (OK!=s) printf("FLOPPY: warning, getuptime failed: %d\n", s);   need_reset = TRUE;		/* controller chip must be reset */  if ((s=sys_irqenable(&irq_hook_id)) != OK)	panic("FLOPPY", "Couldn't enable IRQs", s);  return(ERR_STATUS);}/*===========================================================================* *				fdc_command				     * *===========================================================================*/PRIVATE int fdc_command(cmd, len)u8_t *cmd;		/* command bytes */int len;		/* command length */{/* Output a command to the controller. */  /* Set a synchronous alarm to force a timeout if the hardware does   * not interrupt. Expect HARD_INT, but check for SYN_ALARM timeout.   * Note that the actual check is done by the code that issued the   * fdc_command() call.   */   f_set_timer(&f_tmr_timeout, WAKEUP, f_timeout);  f_busy = BSY_IO;  while (len > 0) {	fdc_out(*cmd++);	len--;  }  return(need_reset ? ERR_DRIVE : OK);}/*===========================================================================* *				fdc_out					     * *===========================================================================*/PRIVATE void fdc_out(val)int val;		/* write this byte to floppy 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.

⌨️ 快捷键说明

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