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

📄 hd.c

📁 arm平台上的uclinux系统全部源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
				}#if (HD_DELAY > 0)				last_req = read_timer();#endif				if (CURRENT)					hd_request();				return;			}		}	}	dump_status("multwrite_intr", i);	bad_rw_intr();	hd_request();}static void write_intr(void){	int i;	int retries = 100000;	if (unmask_intr[DEVICE_NR(WCURRENT.rq_dev)])		sti();	do {		i = (unsigned) inb_p(HD_STATUS);		if (i & BUSY_STAT)			continue;		if (!OK_STATUS(i))			break;		if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))			goto ok_to_write;	} while (--retries > 0);	dump_status("write_intr", i);	bad_rw_intr();	hd_request();	return;ok_to_write:	CURRENT->sector++;	i = --CURRENT->nr_sectors;	--CURRENT->current_nr_sectors;	CURRENT->buffer += 512;	if (!i || (CURRENT->bh && !SUBSECTOR(i)))		end_request(1);	if (i > 0) {		SET_INTR(&write_intr);		outsw(HD_DATA,CURRENT->buffer,256);		sti();	} else {#if (HD_DELAY > 0)		last_req = read_timer();#endif		hd_request();	}	return;}static void recal_intr(void){	check_status();#if (HD_DELAY > 0)	last_req = read_timer();#endif	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){	unsigned int dev;	DEVICE_INTR = NULL;	if (!CURRENT)		return;	disable_irq(HD_IRQ);	sti();	reset = 1;	dev = DEVICE_NR(CURRENT->rq_dev);	printk("hd%c: timeout\n", dev+'a');	if (++CURRENT->errors >= MAX_ERRORS) {#ifdef DEBUG		printk("hd%c: too many errors\n", dev+'a');#endif		end_request(0);	}	cli();	hd_request();	enable_irq(HD_IRQ);}int do_special_op (unsigned int dev){	if (recalibrate[dev]) {		recalibrate[dev] = 0;		hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);		return reset;	}	if (!identified[dev]) {		identified[dev]  = 1;		unmask_intr[dev] = DEFAULT_UNMASK_INTR;		mult_req[dev]    = DEFAULT_MULT_COUNT;		hd_out(dev,0,0,0,0,WIN_IDENTIFY,&identify_intr);		return reset;	}	if (mult_req[dev] != mult_count[dev]) {		hd_out(dev,mult_req[dev],0,0,0,WIN_SETMULT,&set_multmode_intr);		return reset;	}	if (hd_info[dev].head > 16) {		printk ("hd%c: cannot handle device with more than 16 heads - giving up\n", dev+'a');		end_request(0);	}	special_op[dev] = 0;	return 1;}/* * The driver enables interrupts as much as possible.  In order to do this, * (a) the device-interrupt is disabled before entering hd_request(), * and (b) the timeout-interrupt is disabled before the sti(). * * Interrupts are still masked (by default) whenever we are exchanging * data/cmds with a drive, because some drives seem to have very poor * tolerance for latency during I/O.  For devices which don't suffer from * that problem (most don't), the unmask_intr[] flag can be set to unmask * other interrupts during data/cmd transfers (by defining DEFAULT_UNMASK_INTR * to 1, or by using "hdparm -u1 /dev/hd?" from the shell). */static void hd_request(void){	unsigned int dev, block, nsect, sec, track, head, cyl;	if (CURRENT && CURRENT->rq_status == RQ_INACTIVE) return;	if (DEVICE_INTR)		return;repeat:	timer_active &= ~(1<<HD_TIMER);	sti();	INIT_REQUEST;	if (reset) {		cli();		reset_hd();		return;	}	dev = MINOR(CURRENT->rq_dev);	block = CURRENT->sector;	nsect = CURRENT->nr_sectors;	if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects || ((block+nsect) > hd[dev].nr_sects)) {#ifdef DEBUG		if (dev >= (NR_HD<<6))			printk("hd: bad minor number: device=%s\n",			       kdevname(CURRENT->rq_dev));		else			printk("hd%c: bad access: block=%d, count=%d\n",				(MINOR(CURRENT->rq_dev)>>6)+'a', block, nsect);#endif		end_request(0);		goto repeat;	}	block += hd[dev].start_sect;	dev >>= 6;	if (special_op[dev]) {		if (do_special_op(dev))			goto repeat;		return;	}	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%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx\n",		dev+'a', (CURRENT->cmd == READ)?"read":"writ",		cyl, head, sec, nsect, (unsigned long) CURRENT->buffer);#endif	if (!unmask_intr[dev])		cli();	if (CURRENT->cmd == READ) {		unsigned int cmd = mult_count[dev] > 1 ? WIN_MULTREAD : WIN_READ;		hd_out(dev,nsect,sec,head,cyl,cmd,&read_intr);		if (reset)			goto repeat;		return;	}	if (CURRENT->cmd == WRITE) {		if (mult_count[dev])			hd_out(dev,nsect,sec,head,cyl,WIN_MULTWRITE,&multwrite_intr);		else			hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);		if (reset)			goto repeat;		if (wait_DRQ()) {			bad_rw_intr();			goto repeat;		}		if (mult_count[dev]) {			WCURRENT = *CURRENT;			multwrite(dev);		} else			outsw(HD_DATA,CURRENT->buffer,256);		return;	}	panic("unknown hd-command");}static void do_hd_request (void){	disable_irq(HD_IRQ);	hd_request();	enable_irq(HD_IRQ);}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;	unsigned long flags;	if ((!inode) || !(inode->i_rdev))		return -EINVAL;	dev = DEVICE_NR(inode->i_rdev);	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_user(bios_info[dev].head,				(char *) &loc->heads);			put_user(bios_info[dev].sect,				(char *) &loc->sectors);			put_user(bios_info[dev].cyl,				(short *) &loc->cylinders);			put_user(hd[MINOR(inode->i_rdev)].start_sect,				(long *) &loc->start);			return 0;		case BLKRASET:			if(!suser())  return -EACCES;			if(arg > 0xff) return -EINVAL;			read_ahead[MAJOR(inode->i_rdev)] = arg;			return 0;		case BLKRAGET:			if (!arg)  return -EINVAL;			err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));			if (err)				return err;			put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);			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_user(hd[MINOR(inode->i_rdev)].nr_sects, (long *) arg);			return 0;		case BLKFLSBUF:			if(!suser())  return -EACCES;			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);		case HDIO_SET_UNMASKINTR:			if (!suser()) return -EACCES;			if ((arg > 1) || (MINOR(inode->i_rdev) & 0x3F))				return -EINVAL;			unmask_intr[dev] = arg;			return 0;                case HDIO_GET_UNMASKINTR:			if (!arg)  return -EINVAL;			err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));			if (err)				return err;			put_user(unmask_intr[dev], (long *) arg);			return 0;                case HDIO_GET_MULTCOUNT:			if (!arg)  return -EINVAL;			err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));			if (err)				return err;			put_user(mult_count[dev], (long *) arg);			return 0;		case HDIO_SET_MULTCOUNT:			if (!suser()) return -EACCES;			if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;			save_flags(flags);			cli();	/* a prior request might still be in progress */			if (arg > max_mult[dev])				err = -EINVAL;	/* out of range for device */			else if (mult_req[dev] != mult_count[dev]) {				special_op[dev] = 1;				err = -EBUSY;	/* busy, try again */			} else {				mult_req[dev] = arg;				special_op[dev] = 1;				err = 0;			}			restore_flags(flags);			return err;		case HDIO_GET_IDENTITY:			if (!arg)  return -EINVAL;			if (MINOR(inode->i_rdev) & 0x3F) return -EINVAL;			if (hd_ident_info[dev] == NULL)  return -ENOMSG;			err = verify_area(VERIFY_WRITE, (char *) arg, sizeof(struct hd_driveid));			if (err)				return err;			memcpy_tofs((char *)arg, (char *) hd_ident_info[dev], sizeof(struct hd_driveid));			return 0;		RO_IOCTLS(inode->i_rdev,arg);		default:			return -EINVAL;	}}static int hd_open(struct inode * inode, struct file * filp){	int target;	target =  DEVICE_NR(inode->i_rdev);	if (target >= NR_HD)		return -ENODEV;	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(inode->i_rdev);	access_count[target]--;}static void hd_geninit(struct gendisk *);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 *) bios_info,	/* internal */	NULL		/* next */};	static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs){	void (*handler)(void) = DEVICE_INTR;	DEVICE_INTR = NULL;	timer_active &= ~(1<<HD_TIMER);	if (!handler)		handler = unexpected_hd_interrupt;	handler();	sti();}/* * Since we find out the physical drive geometry, we don't touch that. * We only alter the logical disk geometry that is passed to user programs. * [as per PC Linux]. */void hd_set_geometry (kdev_t dev, unsigned char secspertrack, unsigned char heads,		unsigned long discsize, unsigned int secsize){    int minor = MINOR(dev);    int drv = minor >> 6;    if (bios_info[drv].cyl == 1) {	bios_info[drv].cyl = discsize / (secspertrack * heads * secsize);	bios_info[drv].head = heads;	bios_info[drv].wpcom = -1;	bios_info[drv].ctl = 8;	bios_info[drv].lzone = bios_info[drv].cyl - 1;	bios_info[drv].sect = secspertrack;    }    hd[minor].start_sect = 0;    hd[minor].nr_sects = discsize / secsize;}/* * 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 void hd_geninit(struct gendisk *ignored){	int i;	if (!NR_HD) {		int drive;		extern int number_ide_drives;		/*		 * Default settings		 *		 * If we don't know anything about the drive, then set it		 * so that we have enough to read the boot sector of the		 * ADFS drive.  This means that you *MUST* specify the		 * drive parameters of *all* drives if you have one IDE		 * drive that is not ADFS formatted.		 */		for (drive=0 ; drive<2 ; drive++) {			bios_info[drive].cyl   = hd_info[drive].cyl = 1;			bios_info[drive].head  = hd_info[drive].head = 1;			bios_info[drive].wpcom = hd_info[drive].wpcom = -1;			bios_info[drive].ctl   = hd_info[drive].ctl = 8;			bios_info[drive].lzone = hd_info[drive].lzone = 1;			bios_info[drive].sect  = hd_info[drive].sect = 17;		}		/*		 * We only set this to the one that the host OS gave us		 * if the user has not defined any types.		 */		NR_HD = number_ide_drives;	}	i = NR_HD;	while (i-- > 0) {		/*		 * The newer E-IDE BIOSs handle drives larger than 1024		 * cylinders by increasing the number of logical heads		 * to keep the number of logical cylinders below the		 * sacred INT13 limit of 1024 (10 bits).  If that is		 * what's happening here, we'll find out and correct		 * it later when "identifying" the drive.		 */		hd[i<<6].nr_sects = bios_info[i].head *				bios_info[i].sect * bios_info[i].cyl;		hd_ident_info[i] = (struct hd_driveid *) kmalloc(512,GFP_KERNEL);		special_op[i] = 1;	}	if (NR_HD) {		if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {			printk("hd: unable to get IRQ%d for the harddisk driver\n",HD_IRQ);			NR_HD = 0;		} else {			request_region(HD_DATA, 8, "hd");			request_region(HD_CMD, 1, "hd(cmd)");		}	}	hd_gendisk.nr_real = NR_HD;	for (i = 0; i < (MAX_HD << 6); i++) {		hd_blocksizes[i] = 1024;		hd_hardsectsizes[i] = 512;	}	blksize_size[MAJOR_NR] = hd_blocksizes;	hardsect_size[MAJOR_NR] = hd_hardsectsizes;}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 */};int hd_init(void){	if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {		printk("hd: unable to get major %d for harddisk\n",MAJOR_NR);		return -1;	}	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 0;}#define DEVICE_BUSY busy[target]#define USAGE access_count[target]#define CAPACITY (bios_info[target].head*bios_info[target].sect*bios_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(kdev_t dev, int maxusage){	int target;	struct gendisk * gdev;	int max_p;	int start;	int i;	long flags;	target = DEVICE_NR(dev);	gdev = &GENDISK_STRUCT;	save_flags_cli (flags);	if (DEVICE_BUSY || USAGE > maxusage) {		restore_flags(flags);		return -EBUSY;	};	DEVICE_BUSY = 1;	restore_flags(flags);	max_p = gdev->max_p;	start = target << gdev->minor_shift;	for (i=max_p - 1; i >=0 ; i--) {		int minor = start + i;		kdev_t devi = MKDEV(MAJOR_NR, minor);		sync_dev(devi);		invalidate_inodes(devi);		invalidate_buffers(devi);		gdev->part[minor].start_sect = 0;		gdev->part[minor].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 + -