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

📄 floppy.c

📁 带有中文注释的linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
}//// 软盘操作出错中断调用函数。由软驱中断处理程序调用。static voidbad_flp_intr (void){  CURRENT->errors++;		// 当前请求项出错次数增1。// 如果当前请求项出错次数大于最大允许出错次数,则取消选定当前软驱,并结束该请求项(不更新)。  if (CURRENT->errors > MAX_ERRORS)    {      floppy_deselect (current_drive);      end_request (0);    }// 如果当前请求项出错次数大于最大允许出错次数的一半,则置复位标志,需对软驱进行复位操作,// 然后再试。否则软驱需重新校正一下,再试。  if (CURRENT->errors > MAX_ERRORS / 2)    reset = 1;  else    recalibrate = 1;} /*    * Ok, this interrupt is called after a DMA read/write has succeeded,    * so we check the results, and copy any buffers.  *//** OK,下面该中断处理函数是在DMA 读/写成功后调用的,这样我们就可以检查执行结果,* 并复制缓冲区中的数据。*///// 软盘读写操作成功中断调用函数。。static voidrw_interrupt (void){// 如果返回结果字节数不等于7,或者状态字节0、1 或2 中存在出错标志,则若是写保护// 就显示出错信息,释放当前驱动器,并结束当前请求项。否则就执行出错计数处理。// 然后继续执行软盘请求操作。// ( 0xf8 = ST0_INTR | ST0_SE | ST0_ECE | ST0_NR )// ( 0xbf = ST1_EOC | ST1_CRC | ST1_OR | ST1_ND | ST1_WP | ST1_MAM,应该是0xb7)// ( 0x73 = ST2_CM | ST2_CRC | ST2_WC | ST2_BC | ST2_MAM )  if (result () != 7 || (ST0 & 0xf8) || (ST1 & 0xbf) || (ST2 & 0x73))    {      if (ST1 & 0x02)	{			// 0x02 = ST1_WP - Write Protected。	  printk ("Drive %d is write protected\n\r", current_drive);	  floppy_deselect (current_drive);	  end_request (0);	}      else	bad_flp_intr ();      do_fd_request ();      return;    }// 如果当前请求项的缓冲区位于1M 地址以上,则说明此次软盘读操作的内容还放在临时缓冲区内,// 需要复制到请求项的缓冲区中(因为DMA 只能在1M 地址范围寻址)。  if (command == FD_READ && (unsigned long) (CURRENT->buffer) >= 0x100000)    copy_buffer (tmp_floppy_area, CURRENT->buffer);// 释放当前软盘,结束当前请求项(置更新标志),再继续执行其它软盘请求项。  floppy_deselect (current_drive);  end_request (1);  do_fd_request ();}//// 设置DMA 并输出软盘操作命令和参数(输出1 字节命令+ 0~7 字节参数)。inline voidsetup_rw_floppy (void){  setup_DMA ();			// 初始化软盘DMA 通道。  do_floppy = rw_interrupt;	// 置软盘中断调用函数指针。  output_byte (command);	// 发送命令字节。  output_byte (head << 2 | current_drive);	// 发送参数(磁头号+驱动器号)。  output_byte (track);		// 发送参数(磁道号)。  output_byte (head);		// 发送参数(磁头号)。  output_byte (sector);		// 发送参数(起始扇区号)。  output_byte (2);		/* sector size = 512 */// 发送参数(字节数(N=2)512 字节)。  output_byte (floppy->sect);	// 发送参数(每磁道扇区数)。  output_byte (floppy->gap);	// 发送参数(扇区间隔长度)。  output_byte (0xFF);		/* sector size (0xff when n!=0 ?) */// 发送参数(当N=0 时,扇区定义的字节长度),这里无用。// 若在发送命令和参数时发生错误,则继续执行下一软盘操作请求。  if (reset)    do_fd_request ();} /*    * This is the routine called after every seek (or recalibrate) interrupt    * from the floppy controller. Note that the "unexpected interrupt" routine    * also does a recalibrate, but doesn't come here.  *//** 该子程序是在每次软盘控制器寻道(或重新校正)中断后被调用的。注意* "unexpected interrupt"(意外中断)子程序也会执行重新校正操作,但不在此地。*///// 寻道处理中断调用函数。// 首先发送检测中断状态命令,获得状态信息ST0 和磁头所在磁道信息。若出错则执行错误计数// 检测处理或取消本次软盘操作请求项。否则根据状态信息设置当前磁道变量,然后调用函数// setup_rw_floppy()设置DMA 并输出软盘读写命令和参数。static voidseek_interrupt (void){/* sense drive status *//* 检测中断状态 */// 发送检测中断状态命令,该命令不带参数。返回结果信息两个字节:ST0 和磁头当前磁道号。  output_byte (FD_SENSEI);// 如果返回结果字节数不等于2,或者ST0 不为寻道结束,或者磁头所在磁道(ST1)不等于设定磁道,// 则说明发生了错误,于是执行检测错误计数处理,然后继续执行软盘请求项,并退出。  if (result () != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track)    {      bad_flp_intr ();      do_fd_request ();      return;    }  current_track = ST1;		// 设置当前磁道。  setup_rw_floppy ();		// 设置DMA 并输出软盘操作命令和参数。} /*    * This routine is called when everything should be correctly set up    * for the transfer (ie floppy motor is on and the correct floppy is    * selected).  *//** 该函数是在传输操作的所有信息都正确设置好后被调用的(也即软驱马达已开启* 并且已选择了正确的软盘(软驱)。*///// 读写数据传输函数。static voidtransfer (void){// 首先看当前驱动器参数是否就是指定驱动器的参数,若不是就发送设置驱动器参数命令及相应// 参数(参数1:高4 位步进速率,低四位磁头卸载时间;参数2:磁头加载时间)。  if (cur_spec1 != floppy->spec1)    {      cur_spec1 = floppy->spec1;      output_byte (FD_SPECIFY);	// 发送设置磁盘参数命令。      output_byte (cur_spec1);	/* hut etc */// 发送参数。      output_byte (6);		/* Head load time =6ms, DMA */    }// 判断当前数据传输速率是否与指定驱动器的一致,若不是就发送指定软驱的速率值到数据传输// 速率控制寄存器(FD_DCR)。  if (cur_rate != floppy->rate)    outb_p (cur_rate = floppy->rate, FD_DCR);// 若返回结果信息表明出错,则再调用软盘请求函数,并返回。  if (reset)    {      do_fd_request ();      return;    }// 若寻道标志为零(不需要寻道),则设置DMA 并发送相应读写操作命令和参数,然后返回。  if (!seek)    {      setup_rw_floppy ();      return;    }// 否则执行寻道处理。置软盘中断处理调用函数为寻道中断函数。  do_floppy = seek_interrupt;// 如果器始磁道号不等于零则发送磁头寻道命令和参数  if (seek_track)    {      output_byte (FD_SEEK);	// 发送磁头寻道命令。      output_byte (head << 2 | current_drive);	//发送参数:磁头号+当前软驱号。      output_byte (seek_track);	// 发送参数:磁道号。    }  else    {      output_byte (FD_RECALIBRATE);	// 发送重新校正命令。      output_byte (head << 2 | current_drive);	//发送参数:磁头号+当前软驱号。    }// 如果复位标志已置位,则继续执行软盘请求项。  if (reset)    do_fd_request ();} /*    * Special case - used after a unexpected interrupt (or reset)  *//** 特殊情况 - 用于意外中断(或复位)处理后。*///// 软驱重新校正中断调用函数。// 首先发送检测中断状态命令(无参数),如果返回结果表明出错,则置复位标志,否则复位重新// 校正标志。然后再次执行软盘请求。static voidrecal_interrupt (void){  output_byte (FD_SENSEI);	// 发送检测中断状态命令。  if (result () != 2 || (ST0 & 0xE0) == 0x60)	// 如果返回结果字节数不等于2 或命令    reset = 1;			// 异常结束,则置复位标志。  else				// 否则复位重新校正标志。    recalibrate = 0;  do_fd_request ();		// 执行软盘请求项。}//// 意外软盘中断请求中断调用函数。// 首先发送检测中断状态命令(无参数),如果返回结果表明出错,则置复位标志,否则置重新// 校正标志。voidunexpected_floppy_interrupt (void){  output_byte (FD_SENSEI);	// 发送检测中断状态命令。  if (result () != 2 || (ST0 & 0xE0) == 0x60)	// 如果返回结果字节数不等于2 或命令    reset = 1;			// 异常结束,则置复位标志。  else				// 否则置重新校正标志。    recalibrate = 1;}//// 软盘重新校正处理函数。// 向软盘控制器FDC 发送重新校正命令和参数,并复位重新校正标志。static voidrecalibrate_floppy (void){  recalibrate = 0;		// 复位重新校正标志。  current_track = 0;		// 当前磁道号归零。  do_floppy = recal_interrupt;	// 置软盘中断调用函数指针指向重新校正调用函数。  output_byte (FD_RECALIBRATE);	// 发送命令:重新校正。  output_byte (head << 2 | current_drive);	// 发送参数:(磁头号加)当前驱动器号。  if (reset)			// 如果出错(复位标志被置位)则继续执行软盘请求。    do_fd_request ();}//// 软盘控制器FDC 复位中断调用函数。在软盘中断处理程序中调用。// 首先发送检测中断状态命令(无参数),然后读出返回的结果字节。接着发送设定软驱参数命令// 和相关参数,最后再次调用执行软盘请求。static voidreset_interrupt (void){  output_byte (FD_SENSEI);	// 发送检测中断状态命令。  (void) result ();		// 读取命令执行结果字节。  output_byte (FD_SPECIFY);	// 发送设定软驱参数命令。  output_byte (cur_spec1);	/* hut etc */// 发送参数。  output_byte (6);		/* Head load time =6ms, DMA */  do_fd_request ();		// 调用执行软盘请求。} /*    * reset is done by pulling bit 2 of DOR low for a while.  *//* FDC 复位是通过将数字输出寄存器(DOR)位2 置0 一会儿实现的 *///// 复位软盘控制器。static voidreset_floppy (void){  int i;  reset = 0;			// 复位标志置0。  cur_spec1 = -1;  cur_rate = -1;  recalibrate = 1;		// 重新校正标志置位。  printk ("Reset-floppy called\n\r");	// 显示执行软盘复位操作信息。  cli ();			// 关中断。  do_floppy = reset_interrupt;	// 设置在软盘中断处理程序中调用的函数。  outb_p (current_DOR & ~0x04, FD_DOR);	// 对软盘控制器FDC 执行复位操作。  for (i = 0; i < 100; i++)	// 空操作,延迟。    __asm__ ("nop");  outb (current_DOR, FD_DOR);	// 再启动软盘控制器。  sti ();			// 开中断。}//// 软驱启动定时中断调用函数。// 首先检查数字输出寄存器(DOR),使其选择当前指定的驱动器。然后调用执行软盘读写传输// 函数transfer()。static voidfloppy_on_interrupt (void){  /* We cannot do a floppy-select, as that might sleep. We just force it *//* 我们不能任意设置选择的软驱,因为这样做可能会引起进程睡眠。我们只是迫使它自己选择 */  selected = 1;			// 置已选择当前驱动器标志。// 如果当前驱动器号与数字输出寄存器DOR 中的不同,则重新设置DOR 为当前驱动器current_drive。// 定时延迟2 个滴答时间,然后调用软盘读写传输函数transfer()。否则直接调用软盘读写传输函数。  if (current_drive != (current_DOR & 3))    {      current_DOR &= 0xFC;      current_DOR |= current_drive;      outb (current_DOR, FD_DOR);	// 向数字输出寄存器输出当前DOR。      add_timer (2, &transfer);	// 添加定时器并执行传输函数。    }  else    transfer ();		// 执行软盘读写传输函数。}//// 软盘读写请求项处理函数。//voiddo_fd_request (void){  unsigned int block;  seek = 0;// 如果复位标志已置位,则执行软盘复位操作,并返回。  if (reset)    {      reset_floppy ();      return;    }// 如果重新校正标志已置位,则执行软盘重新校正操作,并返回。  if (recalibrate)    {      recalibrate_floppy ();      return;    }// 检测请求项的合法性(参见kernel/blk_drv/blk.h,127)。  INIT_REQUEST;// 将请求项结构中软盘设备号中的软盘类型(MINOR(CURRENT->dev)>>2)作为索引取得软盘参数块。  floppy = (MINOR (CURRENT->dev) >> 2) + floppy_type;// 如果当前驱动器不是请求项中指定的驱动器,则置标志seek,表示需要进行寻道操作。// 然后置请求项设备为当前驱动器。  if (current_drive != CURRENT_DEV)    seek = 1;  current_drive = CURRENT_DEV;// 设置读写起始扇区。因为每次读写是以块为单位(1 块2 个扇区),所以起始扇区需要起码比// 磁盘总扇区数小2 个扇区。否则结束该次软盘请求项,执行下一个请求项。  block = CURRENT->sector;	// 取当前软盘请求项中起始扇区号??block。  if (block + 2 > floppy->size)    {				// 如果block+2 大于磁盘扇区总数,则      end_request (0);		// 结束本次软盘请求项。      goto repeat;    }// 求对应在磁道上的扇区号,磁头号,磁道号,搜寻磁道号(对于软驱读不同格式的盘)。  sector = block % floppy->sect;	// 起始扇区对每磁道扇区数取模,得磁道上扇区号。  block /= floppy->sect;	// 起始扇区对每磁道扇区数取整,得起始磁道数。  head = block % floppy->head;	// 起始磁道数对磁头数取模,得操作的磁头号。  track = block / floppy->head;	// 起始磁道数对磁头数取整,得操作的磁道号。  seek_track = track << floppy->stretch;	// 相应于驱动器中盘类型进行调整,得寻道号。// 如果寻道号与当前磁头所在磁道不同,则置需要寻道标志seek。  if (seek_track != current_track)    seek = 1;  sector++;			// 磁盘上实际扇区计数是从1 算起。  if (CURRENT->cmd == READ)	// 如果请求项中是读操作,则置软盘读命令码。    command = FD_READ;  else if (CURRENT->cmd == WRITE)	// 如果请求项中是写操作,则置软盘写命令码。    command = FD_WRITE;  else    panic ("do_fd_request: unknown command");// 添加定时器,用于指定驱动器到能正常运行所需延迟的时间(滴答数),当定时时间到时就调用// 函数floppy_on_interrupt(),  add_timer (ticks_to_floppy_on (current_drive), &floppy_on_interrupt);}//// 软盘系统初始化。// 设置软盘块设备的请求处理函数(do_fd_request()),并设置软盘中断门(int 0x26,对应硬件// 中断请求信号IRQ6),然后取消对该中断信号的屏蔽,允许软盘控制器FDC 发送中断请求信号。voidfloppy_init (void){  blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;	// = do_fd_request()。  set_trap_gate (0x26, &floppy_interrupt);	//设置软盘中断门 int 0x26(38)。  outb (inb_p (0x21) & ~0x40, 0x21);	// 复位软盘的中断请求屏蔽位,允许// 软盘控制器发送中断请求信号。}

⌨️ 快捷键说明

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