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

📄 ide-pmac.c

📁 at91rm9200处理器ide接口驱动程序源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
			/* UltraDMA modes. */			drive->using_dma = pmac_ide_udma_enable(drive, idx,				pmac_ide[idx].kind == controller_kl_ata4_80);		}		if (!drive->using_dma && (id->dma_mword & 0x0007)) {			/* Normal MultiWord DMA modes. */			drive->using_dma = pmac_ide_mdma_enable(drive, idx);		}		OUT_BYTE(0, IDE_CONTROL_REG);		/* Apply settings to controller */		pmac_ide_selectproc(drive);	}	return 0;}static int __pmacpmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive){	int ix, dstat;	volatile struct dbdma_regs *dma;	byte unit = (drive->select.b.unit & 0x01);	byte ata4;	int reading = 0;	/* Can we stuff a pointer to our intf structure in config_data	 * or select_data in hwif ?	 */	ix = pmac_ide_find(drive);	if (ix < 0)		return 0;			dma = pmac_ide[ix].dma_regs;	ata4 = (pmac_ide[ix].kind == controller_kl_ata4 ||		pmac_ide[ix].kind == controller_kl_ata4_80);		switch (func) {	case ide_dma_off:		printk(KERN_INFO "%s: DMA disabled\n", drive->name);	case ide_dma_off_quietly:		drive->using_dma = 0;		break;	case ide_dma_on:	case ide_dma_check:		pmac_ide_check_dma(drive);		break;	case ide_dma_read:		reading = 1;	case ide_dma_write:		SELECT_READ_WRITE(HWIF(drive),drive,func);		if (!pmac_ide_build_dmatable(drive, ix, !reading))			return 1;		/* Apple adds 60ns to wrDataSetup on reads */		if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) {			out_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE),				pmac_ide[ix].timings[unit] + 				(reading ? 0x00800000UL : 0));			(void)in_le32((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG + _IO_BASE));		}		drive->waiting_for_dma = 1;		if (drive->media != ide_disk)			return 0;		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);		if ((HWGROUP(drive)->rq->cmd == IDE_DRIVE_TASKFILE) &&		    (drive->addressing == 1)) {			ide_task_t *args = HWGROUP(drive)->rq->special;			OUT_BYTE(args->tfRegister[IDE_COMMAND_OFFSET], IDE_COMMAND_REG);		} else if (drive->addressing) {			OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);		} else {			OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);		}	case ide_dma_begin:		out_le32(&dma->control, (RUN << 16) | RUN);		/* Make sure it gets to the controller right now */		(void)in_le32(&dma->control);		break;	case ide_dma_end: /* returns 1 on error, 0 otherwise */		drive->waiting_for_dma = 0;		dstat = in_le32(&dma->status);		out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));		pmac_ide_destroy_dmatable(drive, ix);		/* verify good dma status */		return (dstat & (RUN|DEAD|ACTIVE)) != RUN;	case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */		/* We have to things to deal with here:		 * 		 * - The dbdma won't stop if the command was started		 * but completed with an error without transfering all		 * datas. This happens when bad blocks are met during		 * a multi-block transfer.		 * 		 * - The dbdma fifo hasn't yet finished flushing to		 * to system memory when the disk interrupt occurs.		 * 		 * The trick here is to increment drive->waiting_for_dma,		 * and return as if no interrupt occured. If the counter		 * reach a certain timeout value, we then return 1. If		 * we really got the interrupt, it will happen right away		 * again.		 * Apple's solution here may be more elegant. They issue		 * a DMA channel interrupt (a separate irq line) via a DBDMA		 * NOP command just before the STOP, and wait for both the		 * disk and DBDMA interrupts to have completed.		 */		 		/* If ACTIVE is cleared, the STOP command have passed and		 * transfer is complete.		 */		if (!(in_le32(&dma->status) & ACTIVE))			return 1;		if (!drive->waiting_for_dma)			printk(KERN_WARNING "ide%d, ide_dma_test_irq \				called while not waiting\n", ix);		/* If dbdma didn't execute the STOP command yet, the		 * active bit is still set */		drive->waiting_for_dma++;		if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {			printk(KERN_WARNING "ide%d, timeout waiting \				for dbdma command stop\n", ix);			return 1;		}		udelay(1);		return 0;		/* Let's implement tose just in case someone wants them */	case ide_dma_bad_drive:	case ide_dma_good_drive:		return check_drive_lists(drive, (func == ide_dma_good_drive));	case ide_dma_verbose:		return report_drive_dmaing(drive);	case ide_dma_retune:	case ide_dma_lostirq:	case ide_dma_timeout:		printk(KERN_WARNING "ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func),  func);		return 1;	default:		printk(KERN_WARNING "ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func);		return 1;	}	return 0;}#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */static void __pmacidepmac_sleep_device(ide_drive_t *drive, int i, unsigned base){	int j;		/* FIXME: We only handle the master IDE disk, we shoud	 *        try to fix CD-ROMs here	 */	switch (drive->media) {	case ide_disk:		/* Spin down the drive */		outb(drive->select.all, base+0x60);		(void)inb(base+0x60);		udelay(100);		outb(0x0, base+0x30);		outb(0x0, base+0x20);		outb(0x0, base+0x40);		outb(0x0, base+0x50);		outb(0xe0, base+0x70);		outb(0x2, base+0x160);   		for (j = 0; j < 10; j++) {			int status;			mdelay(100);			status = inb(base+0x70);			if (!(status & BUSY_STAT) && (status & DRQ_STAT))				break;		}		break;	case ide_cdrom:		// todo		break;	case ide_floppy:		// todo		break;	}}#ifdef CONFIG_PMAC_PBOOKstatic void __pmacidepmac_wake_device(ide_drive_t *drive, int used_dma){	/* We force the IDE subdriver to check for a media change	 * This must be done first or we may lost the condition	 *	 * Problem: This can schedule. I moved the block device	 * wakeup almost late by priority because of that.	 */	if (DRIVER(drive) && DRIVER(drive)->media_change)		DRIVER(drive)->media_change(drive);	/* We kick the VFS too (see fix in ide.c revalidate) */	check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));	#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC	/* We re-enable DMA on the drive if it was active. */	/* This doesn't work with the CD-ROM in the media-bay, probably	 * because of a pending unit attention. The problem if that if I	 * clear the error, the filesystem dies.	 */	if (used_dma && !ide_spin_wait_hwgroup(drive)) {		/* Lock HW group */		HWGROUP(drive)->busy = 1;		pmac_ide_check_dma(drive);		HWGROUP(drive)->busy = 0;		if (!list_empty(&drive->queue.queue_head))			ide_do_request(HWGROUP(drive), 0);		spin_unlock_irq(&io_request_lock);	}#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */}static void __pmacidepmac_sleep_interface(int i, unsigned base, int mediabay){	struct device_node* np = pmac_ide[i].node;	/* We clear the timings */	pmac_ide[i].timings[0] = 0;	pmac_ide[i].timings[1] = 0;		/* The media bay will handle itself just fine */	if (mediabay)		return;		/* Disable the bus */	ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 0);}static void __pmacidepmac_wake_interface(int i, unsigned long base, int mediabay){	struct device_node* np = pmac_ide[i].node;	if (!mediabay) {		/* Revive IDE disk and controller */		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 1);		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 1);		mdelay(10);		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 0);	}}static voididepmac_sleep_drive(ide_drive_t *drive, int idx, unsigned long base){	int unlock = 0;	/* Wait for HW group to complete operations */	if (ide_spin_wait_hwgroup(drive)) {		// What can we do here ? Wake drive we had already		// put to sleep and return an error ?	} else {		unlock = 1;		/* Lock HW group */		HWGROUP(drive)->busy = 1;		/* Stop the device */		idepmac_sleep_device(drive, idx, base);	}	if (unlock)		spin_unlock_irq(&io_request_lock);}static voididepmac_wake_drive(ide_drive_t *drive, unsigned long base){	unsigned long flags;	int j;		/* Reset timings */	pmac_ide_selectproc(drive);	mdelay(10);		/* Wait up to 20 seconds for the drive to be ready */	for (j = 0; j < 200; j++) {		int status;		mdelay(100);		outb(drive->select.all, base + 0x60);		if (inb(base + 0x60) != drive->select.all)			continue;		status = inb(base + 0x70);		if (!(status & BUSY_STAT))			break;	}	/* We resume processing on the HW group */	spin_lock_irqsave(&io_request_lock, flags);	HWGROUP(drive)->busy = 0;	if (!list_empty(&drive->queue.queue_head))		ide_do_request(HWGROUP(drive), 0);	spin_unlock_irqrestore(&io_request_lock, flags);			}/* Note: We support only master drives for now. This will have to be * improved if we want to handle sleep on the iMacDV where the CD-ROM * is a slave */static int __pmacidepmac_notify_sleep(struct pmu_sleep_notifier *self, int when){	int i, ret;	unsigned long base;	int big_delay; 	switch (when) {	case PBOOK_SLEEP_REQUEST:		break;	case PBOOK_SLEEP_REJECT:		break;	case PBOOK_SLEEP_NOW:		for (i = 0; i < pmac_ide_count; ++i) {			ide_hwif_t *hwif;			int dn;			if ((base = pmac_ide[i].regbase) == 0)				continue;			hwif = &ide_hwifs[i];			for (dn=0; dn<MAX_DRIVES; dn++) {				if (!hwif->drives[dn].present)					continue;				idepmac_sleep_drive(&hwif->drives[dn], i, base);			}			/* Disable irq during sleep */			disable_irq(pmac_ide[i].irq);						/* Check if this is a media bay with an IDE device or not			 * a media bay.			 */			ret = check_media_bay_by_base(base, MB_CD);			if ((ret == 0) || (ret == -ENODEV))				idepmac_sleep_interface(i, base, (ret == 0));		}		break;	case PBOOK_WAKE:		big_delay = 0;		for (i = 0; i < pmac_ide_count; ++i) {			if ((base = pmac_ide[i].regbase) == 0)				continue;							/* Make sure we have sane timings */					sanitize_timings(i);			/* Check if this is a media bay with an IDE device or not			 * a media bay			 */			ret = check_media_bay_by_base(base, MB_CD);			if ((ret == 0) || (ret == -ENODEV)) {				idepmac_wake_interface(i, base, (ret == 0));								big_delay = 1;			}		}		/* Let hardware get up to speed */		if (big_delay)			mdelay(IDE_WAKEUP_DELAY_MS);			for (i = 0; i < pmac_ide_count; ++i) {			ide_hwif_t *hwif;			int used_dma, dn;			int irq_on = 0;						if ((base = pmac_ide[i].regbase) == 0)				continue;							hwif = &ide_hwifs[i];			for (dn=0; dn<MAX_DRIVES; dn++) {				ide_drive_t *drive = &hwif->drives[dn];				if (!drive->present)					continue;				/* We don't have re-configured DMA yet */				used_dma = drive->using_dma;				drive->using_dma = 0;				idepmac_wake_drive(drive, base);				if (!irq_on) {					enable_irq(pmac_ide[i].irq);					irq_on = 1;				}				idepmac_wake_device(drive, used_dma);			}			if (!irq_on)				enable_irq(pmac_ide[i].irq);		}		break;	}	return PBOOK_SLEEP_OK;}#endif /* CONFIG_PMAC_PBOOK */static int __pmacpmac_ide_notify_reboot(struct notifier_block *this, unsigned long code, void *x){	int i, gotone;	unsigned long base;	if (code != SYS_HALT && code != SYS_POWER_OFF)		return 0;	gotone = 0;	for (i = 0; i < pmac_ide_count; ++i) {		ide_hwif_t *hwif;		ide_drive_t *drive;		int unlock = 0;		int dn;		if ((base = pmac_ide[i].regbase) == 0)				continue;			hwif = &ide_hwifs[i];		for (dn=0; dn<MAX_DRIVES; dn++) {			drive = &hwif->drives[dn];			if (drive->present) {				gotone = 1;				/* Wait for HW group to complete operations */				if (ide_spin_wait_hwgroup(drive)) {					// What can we do here ? Wake drive we had already					// put to sleep and return an error ?				} else {					unlock = 1;					/* Lock HW group */					HWGROUP(drive)->busy = 1;					/* Stop the device */					idepmac_sleep_device(drive, i, base);				}			}			if (unlock)				spin_unlock_irq(&io_request_lock);		}	}	if (gotone)		mdelay(1000);			return NOTIFY_DONE;}

⌨️ 快捷键说明

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