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

📄 ide.c

📁 《嵌入式系统设计与实例开发实验教材II:基于ARM9微处理器与Linux操作系统》IDE—CF卡模块读写实验
💻 C
📖 第 1 页 / 共 5 页
字号:
 */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;	ide_startstop_t startstop;	spin_lock_irqsave(&io_request_lock, flags);	hwif = hwgroup->hwif;	if (!ide_ack_intr(hwif)) {		spin_unlock_irqrestore(&io_request_lock, flags);		return;	}	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:			 */			unexpected_intr(irq, hwgroup);#ifdef CONFIG_BLK_DEV_IDEPCI		} else {			/*			 * Whack the status register, just in case we have a leftover pending IRQ.			 */			(void) IN_BYTE(hwif->io_ports[IDE_STATUS_OFFSET]);#endif /* CONFIG_BLK_DEV_IDEPCI */		}		spin_unlock_irqrestore(&io_request_lock, flags);		return;	}	drive = hwgroup->drive;	if (!drive) {		/*		 * This should NEVER happen, and there isn't much we could do about it here.		 */		spin_unlock_irqrestore(&io_request_lock, flags);		return;	}	if (!drive_is_ready(drive)) {		/*		 * This happens regularly when we share a PCI IRQ with another device.		 * Unfortunately, it can also happen with some buggy drives that trigger		 * the IRQ before their status register is up to date.  Hopefully we have		 * enough advance overhead that the latter isn't a problem.		 */		spin_unlock_irqrestore(&io_request_lock, flags);		return;	}	if (!hwgroup->busy) {		hwgroup->busy = 1;	/* paranoia */		printk("%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);	}	hwgroup->handler = NULL;	del_timer(&hwgroup->timer);	spin_unlock(&io_request_lock);	if (drive->unmask)		ide__sti();	/* local CPU only */	startstop = handler(drive);		/* service this interrupt, may set handler for next interrupt */	spin_lock_irq(&io_request_lock);	/*	 * 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 of the same (on any CPU) until we return.	 */	set_recovery_timer(HWIF(drive));	drive->service_time = jiffies - drive->service_start;	if (startstop == ide_stopped) {		if (hwgroup->handler == NULL) {	/* paranoia */			hwgroup->busy = 0;			ide_do_request(hwgroup, hwif->irq);		} else {			printk("%s: ide_intr: huh? expected NULL handler on exit\n", drive->name);		}	}	spin_unlock_irqrestore(&io_request_lock, flags);}/* * 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. */ide_drive_t *get_info_ptr (kdev_t i_rdev){	int		major = MAJOR(i_rdev);#if 0	int		minor = MINOR(i_rdev) & PARTN_MASK;#endif	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 0				if ((drive->present) && (drive->part[minor].nr_sects))#else				if (drive->present)#endif					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){	memset(rq, 0, sizeof(*rq));	rq->cmd = IDE_DRIVE_CMD;}/* * 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 list_head *queue_head = &drive->queue.queue_head;	DECLARE_COMPLETION(wait);#ifdef CONFIG_BLK_DEV_PDC4030	if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL)		return -ENOSYS;  /* special drive cmds not supported */#endif	rq->errors = 0;	rq->rq_status = RQ_ACTIVE;	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);	if (action == ide_wait)		rq->waiting = &wait;	spin_lock_irqsave(&io_request_lock, flags);	if (list_empty(queue_head) || action == ide_preempt) {		if (action == ide_preempt)			hwgroup->rq = NULL;	} else {		if (action == ide_wait || action == ide_end) {			queue_head = queue_head->prev;		} else			queue_head = queue_head->next;	}	list_add(&rq->queue, queue_head);	ide_do_request(hwgroup, 0);	spin_unlock_irqrestore(&io_request_lock, flags);	if (action == ide_wait) {		wait_for_completion(&wait);	/* wait for it to be serviced */		return rq->errors ? -EIO : 0;	/* return -EIO if errors */	}	return 0;}/* * 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(&io_request_lock, flags);	if (drive->busy || (drive->usage > 1)) {		spin_unlock_irqrestore(&io_request_lock, flags);		return -EBUSY;	};	drive->busy = 1;	MOD_INC_USE_COUNT;	spin_unlock_irqrestore(&io_request_lock, flags);	for (p = 0; p < (1<<PARTN_BITS); ++p) {		if (drive->part[p].nr_sects > 0) {			kdev_t devp = MKDEV(major, minor+p);			invalidate_device(devp, 1);		}		drive->part[p].start_sect = 0;		drive->part[p].nr_sects   = 0;	};	if (DRIVER(drive)->revalidate)		DRIVER(drive)->revalidate(drive);	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_probe_module (void){	if (!ide_probe) {#if defined(CONFIG_KMOD) && defined(CONFIG_BLK_DEV_IDE_MODULE)		(void) request_module("ide-probe-mod");#endif /* (CONFIG_KMOD) && (CONFIG_BLK_DEV_IDE_MODULE) */	} else {		(void) ide_probe->init();	}	revalidate_drives();}static void ide_driver_module (void){	int index;	ide_module_t *module = ide_modules;	for (index = 0; index < MAX_HWIFS; ++index)		if (ide_hwifs[index].present)			goto search;	ide_probe_module();search:	while (module) {		(void) module->init();		module = module->next;	}	revalidate_drives();}static int ide_open (struct inode * inode, struct file * filp){	ide_drive_t *drive;	if ((drive = get_info_ptr(inode->i_rdev)) == NULL)		return -ENXIO;	if (drive->driver == NULL)		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)		return DRIVER(drive)->open(inode, filp, drive);	printk ("%s: driver not present\n", drive->name);	drive->usage--;	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) {		drive->usage--;		if (drive->driver != NULL)			DRIVER(drive)->release(inode, file, drive);	}	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_driver_module();	drive->driver_req[0] = 0;	ide_driver_module();	if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver))		return 0;abort:	return 1;}#ifdef CONFIG_PROC_FSide_proc_entry_t generic_subdriver_entries[] = {	{ "capacity",	S_IFREG|S_IRUGO,	proc_ide_read_capacity,	NULL },	{ NULL, 0, NULL, NULL }};#endif/* * Note that we only release the standard ports, * and do not even try to handle any extra ports * allocated for weird IDE interface chipsets. */void hwif_unregister (ide_hwif_t *hwif){	if (hwif->straight8) {		ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 8);		goto jump_eight;	}	if (hwif->io_ports[IDE_DATA_OFFSET])		ide_release_region(hwif->io_ports[IDE_DATA_OFFSET], 1);	if (hwif->io_ports[IDE_ERROR_OFFSET])		ide_release_region(hwif->io_ports[IDE_ERROR_OFFSET], 1);	if (hwif->io_ports[IDE_NSECTOR_OFFSET])		ide_release_region(hwif->io_ports[IDE_NSECTOR_OFFSET], 1);	if (hwif->io_ports[IDE_SECTOR_OFFSET])		ide_release_region(hwif->io_ports[IDE_SECTOR_OFFSET], 1);	if (hwif->io_ports[IDE_LCYL_OFFSET])		ide_release_region(hwif->io_ports[IDE_LCYL_OFFSET], 1);	if (hwif->io_ports[IDE_HCYL_OFFSET])		ide_release_region(hwif->io_ports[IDE_HCYL_OFFSET], 1);	if (hwif->io_ports[IDE_SELECT_OFFSET])		ide_release_region(hwif->io_ports[IDE_SELECT_OFFSET], 1);	if (hwif->io_ports[IDE_STATUS_OFFSET])		ide_release_region(hwif->io_ports[IDE_STATUS_OFFSET], 1);jump_eight:	if (hwif->io_ports[IDE_CONTROL_OFFSET])		ide_release_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1);#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC)	if (hwif->io_ports[IDE_IRQ_OFFSET])		ide_release_region(hwif->io_ports[IDE_IRQ_OFFSET], 1);#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */}void ide_unregister (unsigned int index){	struct gendisk *gd;	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;	ide_hwif_t old_hwif;	if (index >= MAX_

⌨️ 快捷键说明

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