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

📄 ide.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	del_timer(&hwgroup->timer);	/* Is this needed?? */	if (hwgroup->poll_timeout != 0) {	/* polling in progress? */		spin_unlock_irqrestore(&hwgroup->spinlock, flags);		handler(drive);	} else if (drive_is_ready(drive)) {		printk("%s: lost interrupt\n", drive->name);		spin_unlock_irqrestore(&hwgroup->spinlock, flags);		handler(drive);	} else {		if (drive->waiting_for_dma) {			(void) hwgroup->hwif->dmaproc(ide_dma_end, drive);			printk("%s: timeout waiting for DMA\n", drive->name);	/*	 *  need something here for HX PIIX3 UDMA and HPT343.......AMH	 *  irq timeout: status=0x58 { DriveReady SeekComplete DataRequest }	 */		}		spin_unlock_irqrestore(&hwgroup->spinlock, flags);		ide_error(drive, "irq timeout", GET_STAT());	}	start_next_request(hwgroup, 0);}/* * 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;	ide_hwif_t *hwif = hwgroup->hwif;	/*	 * handle the unexpected interrupt	 */	do {		if (hwif->irq == irq) {			stat = IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);			if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {				/* Try to not flood the console with msgs */				static unsigned long last_msgtime = 0, count = 0;				++count;				if (0 < (signed long)(jiffies - (last_msgtime + HZ))) {					last_msgtime = jiffies;					printk("%s%s: unexpected interrupt, status=0x%02x, count=%ld\n",					 hwif->name, (hwif->next == hwgroup->hwif) ? "" : "(?)", stat, count);				}			}		}	} while ((hwif = hwif->next) != hwgroup->hwif);}/* * entry point for all interrupts, caller does __cli() for us */void ide_intr (int irq, void *dev_id, struct pt_regs *regs){	unsigned long flags;	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;	ide_hwif_t *hwif;	ide_drive_t *drive;	ide_handler_t *handler;	__cli();	/* local CPU only */	spin_lock_irqsave(&hwgroup->spinlock, flags);	hwif = hwgroup->hwif;	if ((handler = hwgroup->handler) == NULL || hwgroup->poll_timeout != 0) {		/*		 * Not expecting an interrupt from this drive.		 * That means this could be:		 *	(1) an interrupt from another PCI device		 *	sharing the same PCI INT# as us.		 * or	(2) a drive just entered sleep or standby mode,		 *	and is interrupting to let us know.		 * or	(3) a spurious interrupt of unknown origin.		 *		 * For PCI, we cannot tell the difference,		 * so in that case we just ignore it and hope it goes away.		 */#ifdef CONFIG_BLK_DEV_IDEPCI		if (IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL))#endif	/* CONFIG_BLK_DEV_IDEPCI */		{			/*			 * Probably not a shared PCI interrupt,			 * so we can safely try to do something about it:			 */			(void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]);			unexpected_intr(irq, hwgroup);		}		spin_unlock_irqrestore(&hwgroup->spinlock, flags);		return;	}	drive = hwgroup->drive;	if (!drive || !drive_is_ready(drive)) {		spin_unlock_irqrestore(&hwgroup->spinlock, flags);		return;	}	hwgroup->handler = NULL;	(void)ide_ack_intr(hwif->io_ports[IDE_STATUS_OFFSET], hwif->io_ports[IDE_IRQ_OFFSET]);	del_timer(&(hwgroup->timer));	{		struct request *rq;		unsigned long block, sectors;		if ((rq = hwgroup->rq) != NULL) {			block = rq->sector;			block += drive->part[MINOR(rq->rq_dev)&PARTN_MASK].start_sect + drive->sect0;			sectors = drive->using_dma ? rq->nr_sectors : drive->mult_count ? drive->mult_count : 1;		}	}	spin_unlock_irqrestore(&hwgroup->spinlock, flags);	if (drive->unmask)		ide__sti();	/* local CPU only */	handler(drive);		/* service this interrupt, may set handler for next interrupt */	/*	 * Note that handler() may have set things up for another	 * interrupt to occur soon, but it cannot happen until	 * we exit from this routine, because it will be the	 * same irq as is currently being serviced here,	 * and Linux won't allow another (on any CPU) until we return.	 */	start_next_request(hwgroup, hwif->irq);}/* * 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;			}			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;}/* * 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. */int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action){	unsigned long flags;	ide_hwgroup_t *hwgroup = HWGROUP(drive);	unsigned int major = HWIF(drive)->major;	struct request *cur_rq;	struct semaphore sem = MUTEX_LOCKED;	if (IS_PDC4030_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;	spin_lock_irqsave(&io_request_lock, flags);	cur_rq = drive->queue;	if (cur_rq == NULL || action == ide_preempt) {		rq->next = cur_rq;		drive->queue = rq;		if (action == ide_preempt)			hwgroup->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;	}	spin_unlock_irqrestore(&io_request_lock, flags);	do_hwgroup_request(hwgroup);	save_flags(flags);	/* all CPUs; overkill? */	cli();			/* all CPUs; overkill? */	if (action == ide_wait && rq->rq_status != RQ_INACTIVE)		down(&sem);	/* wait for it to be serviced */	restore_flags(flags);	/* all CPUs; overkill? */	return rq->errors ? -EIO : 0;	/* return -EIO if errors */}/* * This routine is called to flush all partitions and partition tables * for a changed 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. */int ide_revalidate_disk(kdev_t i_rdev){	ide_drive_t *drive;	ide_hwgroup_t *hwgroup;	unsigned int p, major, minor;	long flags;	if ((drive = get_info_ptr(i_rdev)) == NULL)		return -ENODEV;	major = MAJOR(i_rdev);	minor = drive->select.b.unit << PARTN_BITS;	hwgroup = HWGROUP(drive);	spin_lock_irqsave(&hwgroup->spinlock, flags);	if (drive->busy || (drive->usage > 1)) {		spin_unlock_irqrestore(&hwgroup->spinlock, flags);		return -EBUSY;	};	drive->busy = 1;	MOD_INC_USE_COUNT;	spin_unlock_irqrestore(&hwgroup->spinlock, flags);	for (p = 0; p < (1<<PARTN_BITS); ++p) {		if (drive->part[p].nr_sects > 0) {			kdev_t devp = MKDEV(major, minor+p);			struct super_block * sb = get_super(devp);			fsync_dev          (devp);			if (sb)				invalidate_inodes(sb);			invalidate_buffers (devp);			set_blocksize(devp, 1024);		}		drive->part[p].start_sect = 0;		drive->part[p].nr_sects   = 0;	};	drive->part[0].nr_sects = current_capacity(drive);	if ((drive->media != ide_disk && drive->media != ide_floppy) ||	     drive->driver == NULL || !drive->part[0].nr_sects)		drive->part[0].start_sect = -1;	resetup_one_dev(HWIF(drive)->gd, drive->select.b.unit);	drive->busy = 0;	wake_up(&drive->wqueue);	MOD_DEC_USE_COUNT;	return 0;}static void revalidate_drives (void){	ide_hwif_t *hwif;	ide_drive_t *drive;	int index, unit;	for (index = 0; index < MAX_HWIFS; ++index) {		hwif = &ide_hwifs[index];		for (unit = 0; unit < MAX_DRIVES; ++unit) {			drive = &ide_hwifs[index].drives[unit];			if (drive->revalidate) {				drive->revalidate = 0;				if (!initializing)					(void) ide_revalidate_disk(MKDEV(hwif->major, unit<<PARTN_BITS));			}		}	}}static void ide_init_module (int type){	int found = 0;	ide_module_t *module = ide_modules;		while (module) {		if (module->type == type) {			found = 1;			(void) module->init();		}		module = module->next;	}	revalidate_drives();#ifdef CONFIG_KMOD	if (!found && type == IDE_PROBE_MODULE)		(void) request_module("ide-probe");#endif /* CONFIG_KMOD */}static int ide_open(struct inode * inode, struct file * filp){	ide_drive_t *drive;	int rc;	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)		return -ENXIO;	MOD_INC_USE_COUNT;	if (drive->driver == NULL)		ide_init_module(IDE_DRIVER_MODULE);#ifdef CONFIG_KMOD	if (drive->driver == NULL) {		if (drive->media == ide_disk)			(void) request_module("ide-disk");		if (drive->media == ide_cdrom)			(void) request_module("ide-cd");		if (drive->media == ide_tape)			(void) request_module("ide-tape");		if (drive->media == ide_floppy)			(void) request_module("ide-floppy");	}#endif /* CONFIG_KMOD */	while (drive->busy)		sleep_on(&drive->wqueue);	drive->usage++;	if (drive->driver != NULL) {		if ((rc = DRIVER(drive)->open(inode, filp, drive)))			MOD_DEC_USE_COUNT;		return rc;	}	printk ("%s: driver not present\n", drive->name);	drive->usage--;	MOD_DEC_USE_COUNT;	return -ENXIO;}/* * Releasing a block device means we sync() it, so that it can safely * be forgotten about... */static int ide_release(struct inode * inode, struct file * file){	ide_drive_t *drive;	if ((drive = get_info_ptr(inode->i_rdev)) != NULL) {		fsync_dev(inode->i_rdev);		drive->usage--;		if (drive->driver != NULL)			DRIVER(drive)->release(inode, file, drive);		MOD_DEC_USE_COUNT;	}	return 0;}int ide_replace_subdriver(ide_drive_t *drive, const char *driver){	if (!drive->present || drive->busy || drive->usage)		goto abort;	if (drive->driver != NULL && DRIVER(drive)->cleanup(drive))		goto abort;	strncpy(drive->driver_req, driver, 9);	ide_init_module(IDE_DRIVER_MODULE);	drive->driver_req[0] = 0;	ide_init_module(IDE_DRIVER_MODULE);	if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))		return 0;abort:	return 1;}void ide_unregister (unsigned int index){#ifdef OSKIT	printk(KERN_CRIT "ide_unregister called\n");#else	struct gendisk *gd, **gdp;	ide_drive_t *drive, *d;	ide_hwif_t *hwif, *g;	ide_hwgroup_t *hwgroup;	int irq_count = 0, unit, i;	unsigned long flags;	unsigned int p, minor;	if (index >= MAX_HWIFS)		return;	save_flags(flags);	/* all CPUs */	cli();			/* all CPUs */	hwif = &ide_hwifs[index];	if (!hwif->present)		goto abort;

⌨️ 快捷键说明

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