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

📄 ide.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 5 页
字号:
	((ide_hwgroup_t *)hwif->hwgroup)->drive = drive;#if (DISK_RECOVERY_TIME > 0)	while ((read_timer() - hwif->last_time) < DISK_RECOVERY_TIME);#endif#ifdef CONFIG_BLK_DEV_IDETAPE	POLL_HWIF_TAPE_DRIVE;	/* macro from ide-tape.h */#endif /* CONFIG_BLK_DEV_IDETAPE */	SELECT_DRIVE(hwif,drive);	if (ide_wait_stat(drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) {		printk("%s: drive not ready for command\n", drive->name);		return;	}	if (!drive->special.all) {		if (rq->cmd == IDE_DRIVE_CMD) {			execute_drive_cmd(drive, rq);			return;		}#ifdef CONFIG_BLK_DEV_IDEATAPI		switch (drive->media) {			case ide_disk:				do_rw_disk (drive, rq, block);				return;#ifdef CONFIG_BLK_DEV_IDECD			case ide_cdrom:				ide_do_rw_cdrom (drive, block);				return;#endif /* CONFIG_BLK_DEV_IDECD */#ifdef CONFIG_BLK_DEV_IDETAPE			case ide_tape:				idetape_do_request (drive, rq, block);				return;#endif /* CONFIG_BLK_DEV_IDETAPE */#ifdef CONFIG_BLK_DEV_IDEFLOPPY			case ide_floppy:				idefloppy_do_request (drive, rq, block);				return;#endif /* CONFIG_BLK_DEV_IDEFLOPPY */#ifdef CONFIG_BLK_DEV_IDESCSI			case ide_scsi:				idescsi_do_request (drive, rq, block);				return;#endif /* CONFIG_BLK_DEV_IDESCSI */			default:				printk("%s: media type %d not supported\n",					drive->name, drive->media);				goto kill_rq;		}#else		do_rw_disk (drive, rq, block); /* simpler and faster */		return;#endif /* CONFIG_BLK_DEV_IDEATAPI */	}	do_special(drive);	return;kill_rq:	ide_end_request(0, hwif->hwgroup);}/* * The driver enables interrupts as much as possible.  In order to do this, * (a) the device-interrupt is always masked before entry, and * (b) the timeout-interrupt is always disabled before entry. * * If we enter here from, say irq14, and then start a new request for irq15, * (possible with "serialize" option) then we cannot ensure that we exit * before the irq15 hits us. So, we must be careful not to let this bother us. * * 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 * this problem (most don't), the unmask flag can be set using the "hdparm" * utility, to permit other interrupts during data/cmd transfers. */void ide_do_request (ide_hwgroup_t *hwgroup){	cli();	/* paranoia */	if (hwgroup->handler != NULL) {		printk("%s: EEeekk!! handler not NULL in ide_do_request()\n", hwgroup->hwif->name);		return;	}	do {		ide_hwif_t *hwif = hwgroup->hwif;		struct request *rq;		if ((rq = hwgroup->rq) == NULL) {			if (hwif->sharing_irq && hwgroup->drive) /* set nIEN */				OUT_BYTE(hwgroup->drive->ctl|2,hwif->ctl_port);			/*			 * hwgroup->next_hwif is different from hwgroup->hwif			 * only when a request is inserted using "ide_next".			 * This saves wear and tear on IDE tapes.			 */			hwif = hwgroup->next_hwif;			do {				rq = blk_dev[hwif->major].current_request;				if (rq != NULL && rq->rq_status != RQ_INACTIVE)					goto got_rq;			} while ((hwif = hwif->next) != hwgroup->next_hwif);			hwgroup->active = 0;			return;		/* no work left for this hwgroup */		}	got_rq:		do_request(hwgroup->hwif = hwgroup->next_hwif = hwif, hwgroup->rq = rq);		cli();	} while (hwgroup->handler == NULL);}/* * do_hwgroup_request() invokes ide_do_request() after first masking * all possible interrupts for the current hwgroup.  This prevents race * conditions in the event that an unexpected interrupt occurs while * we are in the driver. * * Note that when an interrupt is used to reenter the driver, the first level * handler will already have masked the irq that triggered, but any other ones * for the hwgroup will still be unmasked.  The driver tries to be careful * about such things. */static void do_hwgroup_request (ide_hwgroup_t *hwgroup){	if (hwgroup->handler == NULL) {		ide_hwif_t *hgif = hwgroup->hwif;		ide_hwif_t *hwif = hgif;		hwgroup->active = 1;		do {			disable_irq(hwif->irq);		} while ((hwif = hwif->next) != hgif);		ide_do_request (hwgroup);		do {			enable_irq(hwif->irq);		} while ((hwif = hwif->next) != hgif);	}}static void do_ide0_request (void)	/* invoked with cli() */{	do_hwgroup_request (ide_hwifs[0].hwgroup);}#if MAX_HWIFS > 1static void do_ide1_request (void)	/* invoked with cli() */{	do_hwgroup_request (ide_hwifs[1].hwgroup);}#endif#if MAX_HWIFS > 2static void do_ide2_request (void)	/* invoked with cli() */{	do_hwgroup_request (ide_hwifs[2].hwgroup);}#endif#if MAX_HWIFS > 3static void do_ide3_request (void)	/* invoked with cli() */{	do_hwgroup_request (ide_hwifs[3].hwgroup);}#endifstatic void timer_expiry (unsigned long data){	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;	ide_drive_t   *drive   = hwgroup->drive;	unsigned long flags;	save_flags(flags);	cli();	if (hwgroup->poll_timeout != 0) { /* polling in progress? */		ide_handler_t *handler = hwgroup->handler;		hwgroup->handler = NULL;		handler(drive);	} else if (hwgroup->handler == NULL) {	 /* not waiting for anything? */		sti(); /* drive must have responded just as the timer expired */		printk("%s: marginal timeout\n", drive->name);	} else {		hwgroup->handler = NULL;	/* abort the operation */		if (hwgroup->hwif->dmaproc)			(void) hwgroup->hwif->dmaproc (ide_dma_abort, drive);		ide_error(drive, "irq timeout", GET_STAT());	}	if (hwgroup->handler == NULL)		do_hwgroup_request (hwgroup);	restore_flags(flags);}/* * There's nothing really useful we can do with an unexpected interrupt, * other than reading the status register (to clear it), and logging it. * There should be no way that an irq can happen before we're ready for it, * so we needn't worry much about losing an "important" interrupt here. * * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the * drive enters "idle", "standby", or "sleep" mode, so if the status looks * "good", we just ignore the interrupt completely. * * This routine assumes cli() is in effect when called. * * If an unexpected interrupt happens on irq15 while we are handling irq14 * and if the two interfaces are "serialized" (CMD640), then it looks like * we could screw up by interfering with a new request being set up for irq15. * * In reality, this is a non-issue.  The new command is not sent unless the * drive is ready to accept one, in which case we know the drive is not * trying to interrupt us.  And ide_set_handler() is always invoked before * completing the issuance of any new drive command, so we will not be * accidently invoked as a result of any valid command completion interrupt. * */static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup){	byte stat;	unsigned int unit;	ide_hwif_t *hwif = hwgroup->hwif;	/*	 * handle the unexpected interrupt	 */	do {		if (hwif->irq == irq) {			for (unit = 0; unit < MAX_DRIVES; ++unit) {				ide_drive_t *drive = &hwif->drives[unit];				if (!drive->present)					continue;				SELECT_DRIVE(hwif,drive);				udelay(100);  /* Ugly, but wait_stat() may not be safe here */				if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT)) {					/* Try to not flood the console with msgs */					static unsigned long last_msgtime = 0;					if ((last_msgtime + (HZ/2)) < jiffies) {						last_msgtime = jiffies;						(void) ide_dump_status(drive, "unexpected_intr", stat);					}				}				if ((stat & DRQ_STAT))					try_to_flush_leftover_data(drive);			}		}	} while ((hwif = hwif->next) != hwgroup->hwif);	SELECT_DRIVE(hwif,hwgroup->drive); /* Ugh.. probably interrupts current I/O */	udelay(100);  /* Ugly, but wait_stat() may not be safe here */}/* * entry point for all interrupts, caller does cli() for us */void ide_intr (int irq, void *dev_id, struct pt_regs *regs){	ide_hwgroup_t *hwgroup = dev_id;	ide_handler_t *handler;	if (irq == hwgroup->hwif->irq && (handler = hwgroup->handler) != NULL) {		ide_drive_t *drive = hwgroup->drive;		hwgroup->handler = NULL;		del_timer(&(hwgroup->timer));		if (drive->unmask)			sti();		handler(drive);		cli();	/* this is necessary, as next rq may be different irq */		if (hwgroup->handler == NULL) {			SET_RECOVERY_TIMER(HWIF(drive)); 			ide_do_request(hwgroup);		}	} else {		unexpected_intr(irq, hwgroup);	}	cli();}/* * get_info_ptr() returns the (ide_drive_t *) for a given device number. * It returns NULL if the given device number does not match any present drives. */static ide_drive_t *get_info_ptr (kdev_t i_rdev){	int		major = MAJOR(i_rdev);	unsigned int	h;	for (h = 0; h < MAX_HWIFS; ++h) {		ide_hwif_t  *hwif = &ide_hwifs[h];		if (hwif->present && major == hwif->major) {			unsigned unit = DEVICE_NR(i_rdev);			if (unit < MAX_DRIVES) {				ide_drive_t *drive = &hwif->drives[unit];				if (drive->present)					return drive;			} else if (major == IDE0_MAJOR && unit < 4) {				printk("ide: probable bad entry for /dev/hd%c\n", 'a'+unit);				printk("ide: to fix it, run:  /usr/src/linux/scripts/MAKEDEV.ide\n");			}			break;		}	}	return NULL;}/* * This function is intended to be used prior to invoking ide_do_drive_cmd(). */void ide_init_drive_cmd (struct request *rq){	rq->buffer = NULL;	rq->cmd = IDE_DRIVE_CMD;	rq->sector = 0;	rq->nr_sectors = 0;	rq->current_nr_sectors = 0;	rq->sem = NULL;	rq->bh = NULL;	rq->bhtail = NULL;	rq->next = NULL;#if 0	/* these are done each time through ide_do_drive_cmd() */	rq->errors = 0;	rq->rq_status = RQ_ACTIVE;	rq->rq_dev = ????;#endif}/* * This function issues a special IDE device request * onto the request queue. * * If action is ide_wait, then the rq is queued at the end of the * request queue, and the function sleeps until it has been processed. * This is for use when invoked from an ioctl handler. * * If action is ide_preempt, then the rq is queued at the head of * the request queue, displacing the currently-being-processed * request and this function returns immediately without waiting * for the new rq to be completed.  This is VERY DANGEROUS, and is * intended for careful use by the ATAPI tape/cdrom driver code. * * If action is ide_next, then the rq is queued immediately after * the currently-being-processed-request (if any), and the function * returns without waiting for the new rq to be completed.  As above, * This is VERY DANGEROUS, and is intended for careful use by the * ATAPI tape/cdrom driver code. * * If action is ide_end, then the rq is queued at the end of the * request queue, and the function returns immediately without waiting * for the new rq to be completed. This is again intended for careful * use by the ATAPI tape/cdrom driver code. (Currently used by ide-tape.c, * when operating in the pipelined operation mode). */int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action){	unsigned long flags;	unsigned int major = HWIF(drive)->major;	struct request *cur_rq;	struct blk_dev_struct *bdev = &blk_dev[major];	struct semaphore sem = MUTEX_LOCKED;	if (IS_PROMISE_DRIVE && rq->buffer != NULL)		return -ENOSYS;  /* special drive cmds not supported */	rq->errors = 0;	rq->rq_status = RQ_ACTIVE;	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);	if (action == ide_wait)		rq->sem = &sem;	unplug_device(bdev);	save_flags(flags);	cli();	if (action == ide_next)		HWGROUP(drive)->next_hwif = HWIF(drive);	cur_rq = bdev->current_request;	if (cur_rq == NULL || action == ide_preempt) {		rq->next = cur_rq;		bdev->current_request = rq;		if (action == ide_preempt)			HWGROUP(drive)->rq = NULL;	} else {		if (action == ide_wait || action == ide_end) {			while (cur_rq->next != NULL)	/* find end of list */				cur_rq = cur_rq->next;		}		rq->next = cur_rq->next;		cur_rq->next = rq;	}	if (!HWGROUP(drive)->active) {		do_hwgroup_request(HWGROUP(drive));		cli();	}	if (action == ide_wait  && rq->rq_status != RQ_INACTIVE)		down(&sem);	/* wait for it to be serviced */	restore_flags(flags);	return rq->errors ? -EIO : 0;	/* return -EIO if errors */}static int ide_open(struct inode * inode, struct file * filp){	ide_dr

⌨️ 快捷键说明

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