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

📄 ide3.c

📁 ucos在三星s3c44b0上的ide程序
💻 C
📖 第 1 页 / 共 5 页
字号:
 * all away */void ide_dma_timeout_retry(ide_drive_t *drive){	ide_hwif_t *hwif = HWIF(drive);	struct request *rq;	/*	 * end current dma transaction	 */	(void) hwif->dmaproc(ide_dma_end, drive);	/*	 * complain a little, later we might remove some of this verbosity	 */	printk("%s: timeout waiting for DMA\n", drive->name);	(void) hwif->dmaproc(ide_dma_timeout, drive);	/*	 * disable dma for now, but remember that we did so because of	 * a timeout -- we'll reenable after we finish this next request	 * (or rather the first chunk of it) in pio.	 */	drive->retry_pio++;	drive->state = DMA_PIO_RETRY;	(void) hwif->dmaproc(ide_dma_off_quietly, drive);	/*	 * un-busy drive etc (hwgroup->busy is cleared on return) and	 * make sure request is sane	 */	rq = HWGROUP(drive)->rq;	HWGROUP(drive)->rq = NULL;	rq->errors = 0;	rq->sector = rq->bh->b_rsector;	rq->current_nr_sectors = rq->bh->b_size >> 9;	rq->buffer = rq->bh->b_data;}/* * ide_timer_expiry() is our timeout function for all drive operations. * But note that it can also be invoked as a result of a "sleep" operation * triggered by the mod_timer() call in ide_do_request. */void ide_timer_expiry (unsigned long data){	ide_hwgroup_t	*hwgroup = (ide_hwgroup_t *) data;	ide_handler_t	*handler;	ide_expiry_t	*expiry; 	unsigned long	flags;	unsigned long	wait;	spin_lock_irqsave(&io_request_lock, flags);	del_timer(&hwgroup->timer);	if ((handler = hwgroup->handler) == NULL) {		/*		 * Either a marginal timeout occurred		 * (got the interrupt just as timer expired),		 * or we were "sleeping" to give other devices a chance.		 * Either way, we don't really want to complain about anything.		 */		if (hwgroup->sleeping) {			hwgroup->sleeping = 0;			hwgroup->busy = 0;		}	} else {		ide_drive_t *drive = hwgroup->drive;		if (!drive) {			printk("ide_timer_expiry: hwgroup->drive was NULL\n");			hwgroup->handler = NULL;		} else {			ide_hwif_t *hwif;			ide_startstop_t startstop;			if (!hwgroup->busy) {				hwgroup->busy = 1;	/* paranoia */				printk("%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);			}			if ((expiry = hwgroup->expiry) != NULL) {				/* continue */				if ((wait = expiry(drive)) != 0) {					/* reset timer */					hwgroup->timer.expires  = jiffies + wait;					add_timer(&hwgroup->timer);					spin_unlock_irqrestore(&io_request_lock, flags);					return;				}			}			hwgroup->handler = NULL;			/*			 * We need to simulate a real interrupt when invoking			 * the handler() function, which means we need to globally			 * mask the specific IRQ:			 */			spin_unlock(&io_request_lock);			hwif  = HWIF(drive);#if DISABLE_IRQ_NOSYNC			disable_irq_nosync(hwif->hw.irq);#else			disable_irq(hwif->hw.irq);	/* disable_irq_nosync ?? */#endif /* DISABLE_IRQ_NOSYNC */			__cli();	/* local CPU only, as if we were handling an interrupt */			if (hwgroup->poll_timeout != 0) {				startstop = handler(drive);			} else if (drive_is_ready(drive)) {				if (drive->waiting_for_dma)					(void) hwgroup->hwif->dmaproc(ide_dma_lostirq, drive);				(void)ide_ack_intr(hwif);				printk("%s: lost interrupt\n", drive->name);				startstop = handler(drive);			} else {				if (drive->waiting_for_dma) {					startstop = ide_stopped;					ide_dma_timeout_retry(drive);				} else					startstop = ide_error(drive, "irq timeout", GET_STAT());			}			set_recovery_timer(hwif);			drive->service_time = jiffies - drive->service_start;			enable_irq(hwif->hw.irq);			spin_lock_irq(&io_request_lock);			if (startstop == ide_stopped)				hwgroup->busy = 0;		}	}	ide_do_request(hwgroup, 0);	spin_unlock_irqrestore(&io_request_lock, 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 * accidentally 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->hw.irq == irq) {			stat = IN_BYTE(hwif->hw.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, count;				++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;	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->hw.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->hw.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;	unsigned 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_irqre

⌨️ 快捷键说明

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