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

📄 hd.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 2 页
字号:
#endif		do_hd_request();	}	return;}static void recal_intr(void){	if (win_result())		bad_rw_intr();	do_hd_request();}/* * This is another of the error-routines I don't know what to do with. The * best idea seems to just set reset, and start all over again. */static void hd_times_out(void){	DEVICE_INTR = NULL;	sti();	reset = 1;	if (!CURRENT)		return;	printk(KERN_DEBUG "HD timeout\n");	cli();	if (++CURRENT->errors >= MAX_ERRORS) {#ifdef DEBUG		printk("hd : too many errors.\n");#endif		end_request(0);	}	do_hd_request();}/* * The driver has been modified to enable interrupts a bit more: in order to * do this we first (a) disable the timeout-interrupt and (b) clear the * device-interrupt. This way the interrupts won't mess with out code (the * worst that can happen is that an unexpected HD-interrupt comes in and * sets the "reset" variable and starts the timer) */static void do_hd_request(void){	unsigned int block,dev;	unsigned int sec,head,cyl,track;	unsigned int nsect;	if (CURRENT && CURRENT->dev < 0) return;	if (DEVICE_INTR)		return;repeat:	timer_active &= ~(1<<HD_TIMER);	sti();	INIT_REQUEST;	dev = MINOR(CURRENT->dev);	block = CURRENT->sector;	nsect = CURRENT->nr_sectors;	if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {#ifdef DEBUG		printk("hd%d : attempted read for sector %d past end of device at sector %d.\n",		   	block, hd[dev].nr_sects);#endif		end_request(0);		goto repeat;	}	block += hd[dev].start_sect;	dev >>= 6;	sec = block % hd_info[dev].sect + 1;	track = block / hd_info[dev].sect;	head = track % hd_info[dev].head;	cyl = track / hd_info[dev].head;#ifdef DEBUG	printk("hd%d : cyl = %d, head = %d, sector = %d, buffer = %08x\n",		dev, cyl, head, sec, CURRENT->buffer);#endif	cli();	if (reset) {		int i;		for (i=0; i < NR_HD; i++)			recalibrate[i] = 1;		reset_hd();		sti();		return;	}	if (recalibrate[dev]) {		recalibrate[dev] = 0;		hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);		if (reset)			goto repeat;		sti();		return;	}		if (CURRENT->cmd == WRITE) {		hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);		if (reset)			goto repeat;		if (wait_DRQ()) {			printk("HD: do_hd_request: no DRQ\n");			bad_rw_intr();			goto repeat;		}		outsw(HD_DATA,CURRENT->buffer,256);		sti();		return;	}	if (CURRENT->cmd == READ) {		hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);		if (reset)			goto repeat;		sti();		return;	}	panic("unknown hd-command");}static int hd_ioctl(struct inode * inode, struct file * file,	unsigned int cmd, unsigned long arg){	struct hd_geometry *loc = (struct hd_geometry *) arg;	int dev, err;	if (!inode)		return -EINVAL;	dev = MINOR(inode->i_rdev) >> 6;	if (dev >= NR_HD)		return -EINVAL;	switch (cmd) {		case HDIO_GETGEO:			if (!loc)  return -EINVAL;			err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));			if (err)				return err;			put_fs_byte(hd_info[dev].head,				(char *) &loc->heads);			put_fs_byte(hd_info[dev].sect,				(char *) &loc->sectors);			put_fs_word(hd_info[dev].cyl,				(short *) &loc->cylinders);			put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,				(long *) &loc->start);			return 0;         	case BLKGETSIZE:   /* Return device size */			if (!arg)  return -EINVAL;			err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));			if (err)				return err;			put_fs_long(hd[MINOR(inode->i_rdev)].nr_sects,				(long *) arg);			return 0;		case BLKFLSBUF:			if(!suser())  return -EACCES;			if(!inode->i_rdev) return -EINVAL;			fsync_dev(inode->i_rdev);			invalidate_buffers(inode->i_rdev);			return 0;		case BLKRRPART: /* Re-read partition tables */			return revalidate_hddisk(inode->i_rdev, 1);		RO_IOCTLS(inode->i_rdev,arg);		default:			return -EINVAL;	}}static int hd_open(struct inode * inode, struct file * filp){	int target;	target =  DEVICE_NR(MINOR(inode->i_rdev));	while (busy[target])		sleep_on(&busy_wait);	access_count[target]++;	return 0;}/* * Releasing a block device means we sync() it, so that it can safely * be forgotten about... */static void hd_release(struct inode * inode, struct file * file){        int target;	sync_dev(inode->i_rdev);	target =  DEVICE_NR(MINOR(inode->i_rdev));	access_count[target]--;}static void hd_geninit(void);static struct gendisk hd_gendisk = {	MAJOR_NR,	/* Major number */		"hd",		/* Major name */	6,		/* Bits to shift to get real from partition */	1 << 6,		/* Number of partitions per real */	MAX_HD,		/* maximum number of real */	hd_geninit,	/* init function */	hd,		/* hd struct */	hd_sizes,	/* block sizes */	0,		/* number */	(void *) hd_info,	/* internal */	NULL		/* next */};	static void hd_interrupt(int unused){	void (*handler)(void) = DEVICE_INTR;	DEVICE_INTR = NULL;	timer_active &= ~(1<<HD_TIMER);	if (!handler)		handler = unexpected_hd_interrupt;	handler();	sti();}/* * This is the harddisk IRQ description. The SA_INTERRUPT in sa_flags * means we run the IRQ-handler with interrupts disabled: this is bad for * interrupt latency, but anything else has led to problems on some * machines... * * We enable interrupts in some of the routines after making sure it's * safe. */static struct sigaction hd_sigaction = {	hd_interrupt,	0,	SA_INTERRUPT,	NULL};static void hd_geninit(void){	int drive, i;	extern struct drive_info drive_info;	unsigned char *BIOS = (unsigned char *) &drive_info;	int cmos_disks;	if (!NR_HD) {	   		for (drive=0 ; drive<2 ; drive++) {			hd_info[drive].cyl = *(unsigned short *) BIOS;			hd_info[drive].head = *(2+BIOS);			hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);			hd_info[drive].ctl = *(8+BIOS);			hd_info[drive].lzone = *(unsigned short *) (12+BIOS);			hd_info[drive].sect = *(14+BIOS);			BIOS += 16;		}	/*		We querry CMOS about hard disks : it could be that 		we have a SCSI/ESDI/etc controller that is BIOS		compatable with ST-506, and thus showing up in our		BIOS table, but not register compatable, and therefore		not present in CMOS.		Furthurmore, we will assume that our ST-506 drives		<if any> are the primary drives in the system, and 		the ones reflected as drive 1 or 2.		The first drive is stored in the high nibble of CMOS		byte 0x12, the second in the low nibble.  This will be		either a 4 bit drive type or 0xf indicating use byte 0x19 		for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.		Needless to say, a non-zero value means we have 		an AT controller hard disk for that drive.			*/		if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)			if (cmos_disks & 0x0f)				NR_HD = 2;			else				NR_HD = 1;	}	i = NR_HD;	while (i-- > 0) {		hd[i<<6].nr_sects = 0;		if (hd_info[i].head > 16) {			printk("hd.c: ST-506 interface disk with more than 16 heads detected,\n");			printk("  probably due to non-standard sector translation. Giving up.\n");			printk("  (disk %d: cyl=%d, sect=%d, head=%d)\n", i,				hd_info[i].cyl,				hd_info[i].sect,				hd_info[i].head);			if (i+1 == NR_HD)				NR_HD--;			continue;		}		hd[i<<6].nr_sects = hd_info[i].head*				hd_info[i].sect*hd_info[i].cyl;	}	if (NR_HD) {		if (irqaction(HD_IRQ,&hd_sigaction)) {			printk("hd.c: unable to get IRQ%d for the harddisk driver\n",HD_IRQ);			NR_HD = 0;		}	}	hd_gendisk.nr_real = NR_HD;	for(i=0;i<(MAX_HD << 6);i++) hd_blocksizes[i] = 1024;	blksize_size[MAJOR_NR] = hd_blocksizes;}static struct file_operations hd_fops = {	NULL,			/* lseek - default */	block_read,		/* read - general block-dev read */	block_write,		/* write - general block-dev write */	NULL,			/* readdir - bad */	NULL,			/* select */	hd_ioctl,		/* ioctl */	NULL,			/* mmap */	hd_open,		/* open */	hd_release,		/* release */	block_fsync		/* fsync */};unsigned long hd_init(unsigned long mem_start, unsigned long mem_end){	if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {		printk("Unable to get major %d for harddisk\n",MAJOR_NR);		return mem_start;	}	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;	read_ahead[MAJOR_NR] = 8;		/* 8 sector (4kB) read-ahead */	hd_gendisk.next = gendisk_head;	gendisk_head = &hd_gendisk;	timer_table[HD_TIMER].fn = hd_times_out;	return mem_start;}#define DEVICE_BUSY busy[target]#define USAGE access_count[target]#define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)/* We assume that the the bios parameters do not change, so the disk capacity   will not change */#undef MAYBE_REINIT#define GENDISK_STRUCT hd_gendisk/* * This routine is called to flush all partitions and partition tables * for a changed scsi disk, and then re-read the new partition table. * If we are revalidating a disk because of a media change, then we * enter with usage == 0.  If we are using an ioctl, we automatically have * usage == 1 (we need an open channel to use an ioctl :-), so this * is our limit. */static int revalidate_hddisk(int dev, int maxusage){	int target, major;	struct gendisk * gdev;	int max_p;	int start;	int i;	target =  DEVICE_NR(MINOR(dev));	gdev = &GENDISK_STRUCT;	cli();	if (DEVICE_BUSY || USAGE > maxusage) {		sti();		return -EBUSY;	};	DEVICE_BUSY = 1;	sti();	max_p = gdev->max_p;	start = target << gdev->minor_shift;	major = MAJOR_NR << 8;	for (i=max_p - 1; i >=0 ; i--) {		sync_dev(major | start | i);		invalidate_inodes(major | start | i);		invalidate_buffers(major | start | i);		gdev->part[start+i].start_sect = 0;		gdev->part[start+i].nr_sects = 0;	};#ifdef MAYBE_REINIT	MAYBE_REINIT;#endif	gdev->part[start].nr_sects = CAPACITY;	resetup_one_dev(gdev, target);	DEVICE_BUSY = 0;	wake_up(&busy_wait);	return 0;}

⌨️ 快捷键说明

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