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

📄 floppy.c

📁 全中文注释的Linux源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
  	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 void rw_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 void setup_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 void seek_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 void transfer (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 void recal_interrupt (void){	output_byte (FD_SENSEI);					/* 发送检测中断状态命令*/	if (result () != 2 || (ST0 & 0xE0) == 0x60)	/* 如果返回结果字节数不等于2 或命令*/    		reset = 1;							/* 异常结束,则置复位标志*/  	else										/* 否则复位重新校正标志*/    		recalibrate = 0;	do_fd_request ();						/* 执行软盘请求项*/}//// 意外软盘中断请求中断调用函数。// 首先发送检测中断状态命令(无参数),如果返回结果表明出错,则置复位标志,否则置重新// 校正标志。void unexpected_floppy_interrupt (void){	output_byte (FD_SENSEI);					/* 发送检测中断状态命令*/	if (result () != 2 || (ST0 & 0xE0) == 0x60)	/* 如果返回结果字节数不等于2 或命令*/    		reset = 1;							/* 异常结束,则置复位标志*/  	else										/* 否则置重新校正标志*/    		recalibrate = 1;}//// 软盘重新校正处理函数。// 向软盘控制器FDC 发送重新校正命令和参数,并复位重新校正标志。static void recalibrate_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 void reset_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 void reset_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 void floppy_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 ();							/* 执行软盘读写传输函数*/  	}}//// 软盘读写请求项处理函数。//void do_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;					/* 取当前软盘请求项中起始扇区号*/  	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 发送中断请求信号。void floppy_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 + -