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

📄 hd.c

📁 全中文注释的Linux源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/** linux/kernel/hd.c** (C) 1991 Linus Torvalds*//** This is the low-level hd interrupt support. It traverses the* request-list, using interrupts to jump between functions. As* all the functions are called within interrupts, we may not* sleep. Special care is recommended.** modified by Drew Eckhardt to check nr of hd's from the CMOS.*//** 本程序是底层硬盘中断辅助程序。主要用于扫描请求列表,使用中断在函数之间跳转。* 由于所有的函数都是在中断里调用的,所以这些函数不可以睡眠。请特别注意。* 由Drew Eckhardt 修改,利用CMOS 信息检测硬盘数。*/#include <linux/config.h>	/* 内核配置头文件。定义键盘语言和硬盘类型(HD_TYPE)可选项*/#include <linux/sched.h>	/* 调度程序头文件,定义了任务结构task_struct、初始任务0 的数据*/						// 还有一些有关描述符参数设置和获取的嵌入式汇编函数宏语句。#include <linux/fs.h>		/* 文件系统头文件。定义文件表结构(file,buffer_head,m_inode 等)。*/#include <linux/kernel.h>	/* 内核头文件。含有一些内核常用函数的原形定义。*/#include <linux/hdreg.h>	/* 硬盘参数头文件。定义访问硬盘寄存器端口,状态码,分区表等信息。*/#include <asm/system.h>   /* 系统头文件。定义了设置或修改描述符/中断门等的嵌入式汇编宏。*/#include <asm/io.h>		/*  io 头文件。定义硬件端口输入/输出宏汇编语句。*/#include <asm/segment.h>	/*  段操作头文件。定义了有关段寄存器操作的嵌入式汇编函数。*/#define MAJOR_NR 3		/* 硬盘主设备号是3。*/#include "blk.h"		       /* 块设备头文件。定义请求数据结构、块设备数据结构和宏函数等信息*/#define CMOS_READ(addr) ({ \	/* 读CMOS 参数宏函数。*/							outb_p (0x80 | addr, 0x70);							inb_p (0x71);						}						)							/* Max read/write errors/sector */#define MAX_ERRORS 7		   	/* 读/写一个扇区时允许的最多出错次数。*/#define MAX_HD 2		          	/* 系统支持的最多硬盘数。*/static void recal_intr (void);	/* 硬盘中断程序在复位操作时会调用的重新校正函数(287 行)。*/static int recalibrate = 1;		/* 重新校正标志。*/static int reset = 1;	       	/*  复位标志。*//** This struct defines the HD's and their types.*//* 下面结构定义了硬盘参数及类型 */struct hd_i_struct{	int head,			//磁头数	int sect, 			//每磁道扇区数	int cyl, 			//柱面数	int wpcom, 		//写前预补偿柱面号	int lzone, 		//磁头着陆区柱面号	int ctl;			//控制字节};#ifdef HD_TYPE								/* 如果已经在include/linux/config.h 中定义了HD_TYPE */	struct hd_i_struct hd_info[] = { HD_TYPE };	/* 取定义好的参数作为hd_info[]的数据*/	#define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))	/*计算硬盘数*/#else /* 否则,都设为0 值*/	struct hd_i_struct hd_info[] =	{  		{ 0, 0, 0, 0, 0, 0},  		{ 0, 0, 0, 0, 0, 0},	};	static int NR_HD = 0;#endif// 定义硬盘分区结构。给出每个分区的物理起始扇区号、分区扇区总数。// 其中5 的倍数处的项(例如hd[0]和hd[5]等)代表整个硬盘中的参数。static struct hd_struct{	long start_sect;	long nr_sects;}hd[5 * MAX_HD] ={	{0, 0},};// 读端口port,共读nr 字,保存在buf 中。#define port_read(port,buf,nr) \__asm__( "cld;rep;insw":: "d" (port), "D" (buf), "c" (nr): "cx", "di")// 写端口port,共写nr 字,从buf 中取数据。#define port_write(port,buf,nr) \__asm__( "cld;rep;outsw":: "d" (port), "S" (buf), "c" (nr): "cx", "si")extern void hd_interrupt (void);extern void rd_load (void);/* This may be used only once, enforced by 'static int callable' *//* 下面该函数只在初始化时被调用一次。用静态变量callable 作为可调用标志。*/// 该函数的参数由初始化程序init/main.c 的init 子程序设置为指向0x90080 处,此处存放着setup.s// 程序从BIOS 取得的2 个硬盘的基本参数表(32 字节)。硬盘参数表信息参见下面列表后的说明。// 本函数主要功能是读取CMOS 和硬盘参数表信息,用于设置硬盘分区结构hd,并加载RAM 虚拟盘和// 根文件系统。int sys_setup (void *BIOS){	static int callable = 1;			//程序只能调用一次  	int i, drive;  	unsigned char cmos_disks;  	struct partition *p;  	struct buffer_head *bh;	// 初始化时callable=1,当运行该函数时将其设置为0,使本函数只能执行一次。  	if (!callable)      		return -1;	    	callable = 0;	// 如果没有在config.h 中定义硬盘参数,就从0x90080 处读入。	#ifndef HD_TYPE 	for (drive = 0; drive < 2; drive++)    	{      		hd_info[drive].cyl = *(unsigned short *) BIOS;			// 柱面数。      		hd_info[drive].head = *(unsigned char *) (2 + BIOS);	// 磁头数。      		hd_info[drive].wpcom = *(unsigned short *) (5 + BIOS);	// 写前预补偿柱面号。      		hd_info[drive].ctl = *(unsigned char *) (8 + BIOS);		// 控制字节。      		hd_info[drive].lzone = *(unsigned short *) (12 + BIOS);	// 磁头着陆区柱面号。      		hd_info[drive].sect = *(unsigned char *) (14 + BIOS);	// 每磁道扇区数。      		BIOS += 16;		// 每个硬盘的参数表长16 字节,这里BIOS 指向下一个表。    	}		// setup.s 程序在取BIOS 中的硬盘参数表信息时,如果只有1 个硬盘,就会将对应第2 个硬盘的	// 16 字节全部清零。因此这里只要判断第2 个硬盘柱面数是否为0 就可以知道有没有第2 个硬盘了。  	if (hd_info[1].cyl)      		NR_HD = 2;		// 硬盘数置为2。	else    		NR_HD = 1;		#endif	// 设置每个硬盘的起始扇区号和扇区总数。其中编号i*5 含义参见本程序后的有关说明。  	for (i = 0; i < NR_HD; i++)    	{      		hd[i * 5].start_sect = 0;											// 硬盘起始扇区号。      		hd[i * 5].nr_sects = hd_info[i].head * hd_info[i].sect * hd_info[i].cyl;	// 硬盘总扇区数。    	}	/*	* 我们对CMOS 有关硬盘的信息有些怀疑:可能会出现这样的情况,我们有一块SCSI/ESDI/等的	* 控制器,它是以ST-506 方式与BIOS 兼容的,因而会出现在我们的BIOS 参数表中,但却又不	* 是寄存器兼容的,因此这些参数在CMOS 中又不存在。	* 另外,我们假设ST-506 驱动器(如果有的话)是系统中的基本驱动器,也即以驱动器1 或2	* 出现的驱动器。	* 第1 个驱动器参数存放在CMOS 字节0x12 的高半字节中,第2 个存放在低半字节中。该4 位字节	* 信息可以是驱动器类型,也可能仅是0xf。0xf 表示使用CMOS 中0x19 字节作为驱动器1 的8 位	* 类型字节,使用CMOS 中0x1A 字节作为驱动器2 的类型字节。	* 总之,一个非零值意味着我们有一个AT 控制器硬盘兼容的驱动器。	*/	// 这里根据上述原理来检测硬盘到底是否是AT 控制器兼容的。有关CMOS 信息请参见4.2.3.1 节。	if ((cmos_disks = CMOS_READ (0x12)) & 0xf0)    		if (cmos_disks & 0x0f)      			NR_HD = 2;    		else      			NR_HD = 1;  	else    		NR_HD = 0;		// 若NR_HD=0,则两个硬盘都不是AT 控制器兼容的,硬盘数据结构清零。	// 若NR_HD=1,则将第2 个硬盘的参数清零。  	for (i = NR_HD; i < 2; i++)    	{      		hd[i * 5].start_sect = 0;      		hd[i * 5].nr_sects = 0;    	}		// 读取每一个硬盘上第1 块数据(第1 个扇区有用),获取其中的分区表信息。	// 首先利用函数bread()读硬盘第1 块数据(fs/buffer.c,267),参数中的0x300 是硬盘的主设备号	// (参见列表后的说明)。然后根据硬盘头1 个扇区位置0x1fe 处的两个字节是否为'55AA'来判断	// 该扇区中位于0x1BE 开始的分区表是否有效。最后将分区表信息放入硬盘分区数据结构hd 中。  	for (drive = 0; drive < NR_HD; drive++)    	{      		if (!(bh = bread (0x300 + drive * 5, 0)))		{				/* 0x300, 0x305 逻辑设备号*/	  		printk ("Unable to read partition table of drive %d\n\r", drive);	  		panic ("");		}			      		if (bh->b_data[510] != 0x55 || (unsigned char) bh->b_data[511] != 0xAA)		{				/* 判断硬盘信息有效标志'55AA' */	  		printk ("Bad partition table on drive %d\n\r", drive);	  		panic ("");		}		/* 分区表位于硬盘第1 扇区的0x1BE 处*/	      		p = 0x1BE + (void *) bh->b_data;	      		for (i = 1; i < 5; i++, p++)		{	  		hd[i + 5 * drive].start_sect = p->start_sect;	  		hd[i + 5 * drive].nr_sects = p->nr_sects;		}		/* 释放为存放硬盘块而申请的内存缓冲区页*/			      		brelse (bh);		    	} 	if (NR_HD)			/* 如果有硬盘存在并且已读入分区表,则打印分区表正常信息*/    		printk ("Partition table%s ok.\n\r", (NR_HD > 1) ? "s" : "");	rd_load ();			/* 加载(创建)RAMDISK(kernel/blk_drv/ramdisk.c,71) */ 	mount_root ();		/* 安装根文件系统(fs/super.c,242) */  	return (0);}//// 判断并循环等待驱动器就绪。// 读硬盘控制器状态寄存器端口HD_STATUS(0x1f7),并循环检测驱动器就绪比特位和控制器忙位。static int controller_ready (void){	int retries = 10000;	while (--retries && (inb_p (HD_STATUS) & 0xc0) != 0x40);    	return (retries);		/* 返回等待循环的次数*/}//// 检测硬盘执行命令后的状态。(win_表示温切斯特硬盘的缩写)// 读取状态寄存器中的命令执行结果状态。返回0 表示正常,1 出错。如果执行命令错,// 则再读错误寄存器HD_ERROR(0x1f1)。static int win_result (void){	int i = inb_p (HD_STATUS);	/* 取状态信息*/  	if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)) == (READY_STAT | SEEK_STAT))      		return (0);			/* ok */	  	if (i & 1)      		i = inb (HD_ERROR);	/* 若ERR_STAT 置位,则读取错误寄存器*/    	return (1);}// 向硬盘控制器发送命令块(参见列表后的说明)。// 调用参数:drive - 硬盘号(0-1); nsect - 读写扇区数;// sect - 起始扇区; head - 磁头号;// cyl - 柱面号; cmd - 命令码;// *intr_addr() - 硬盘中断处理程序中将调用的C 处理函数。

⌨️ 快捷键说明

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