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

📄 ide-pmac.c

📁 em85xx的大硬盘修正代码包
💻 C
📖 第 1 页 / 共 3 页
字号:
	}#ifdef IDE_PMAC_DEBUG	printk(KERN_INFO "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n",		feature & 0xf, *timings);#endif	drive->current_speed = feature;		return 1;}/* Calculate Ultra DMA timings */static intpmac_ide_udma_enable(ide_drive_t *drive, int idx){	byte bits = drive->id->dma_ultra & 0x1f;	byte feature = udma_bits_to_command(bits);	int cycleTime, accessTime;	int rdyToPauseTicks, cycleTicks;	u32 *timings;	int ret;	/* Set feature on drive */    	printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf);	ret = pmac_ide_do_setfeature(drive, feature);	if (ret) {		printk(KERN_WARNING "%s: Failed !\n", drive->name);		return 0;	}	if (!drive->init_speed)		drive->init_speed = feature;	/* which drive is it ? */	if (drive->select.all & 0x10)		timings = &pmac_ide[idx].timings[1];	else		timings = &pmac_ide[idx].timings[0];	cycleTime = udma_timings[feature & 0xf].cycleTime;	accessTime = udma_timings[feature & 0xf].accessTime;	rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000);	cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000);	*timings = ((*timings) & 0xe00fffff) |			((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20;	drive->current_speed = feature;		return 1;}static intpmac_ide_check_dma(ide_drive_t *drive){	int ata4, udma, idx;	struct hd_driveid *id = drive->id;	int enable = 1;	drive->using_dma = 0;		idx = pmac_ide_find(drive);	if (idx < 0)		return 0;			if (drive->media == ide_floppy)		enable = 0;	if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE))		enable = 0;	if (check_drive_lists(drive, BAD_DMA_DRIVE))		enable = 0;	udma = 0;	ata4 = (pmac_ide[idx].kind == controller_kl_ata4);				if(enable) {		if (ata4 && (drive->media == ide_disk) &&		    (id->field_valid & 0x0004) && (id->dma_ultra & 0x17)) {			/* UltraDMA modes. */			drive->using_dma = pmac_ide_udma_enable(drive, idx);		}		if (!drive->using_dma && (id->dma_mword & 0x0007)) {			/* Normal MultiWord DMA modes. */			drive->using_dma = pmac_ide_mdma_enable(drive, idx);		}		/* Without this, strange things will happen on Keylargo-based		 * machines		 */		OUT_BYTE(0, IDE_CONTROL_REG);		/* Apply settings to controller */		pmac_ide_selectproc(drive);	}	return 0;}int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive){	int ix, dstat, i;	volatile struct dbdma_regs *dma;	/* 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;	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:	case ide_dma_write:		if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write))			return 1;		drive->waiting_for_dma = 1;		if (drive->media != ide_disk)			return 0;		ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL);		OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA,			 IDE_COMMAND_REG);	case ide_dma_begin:		out_le32(&dma->control, (RUN << 16) | RUN);		break;	case ide_dma_end:		drive->waiting_for_dma = 0;		dstat = in_le32(&dma->status);		out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16));		/* verify good dma status */		return (dstat & (RUN|DEAD|ACTIVE)) != RUN;	case ide_dma_test_irq:		if ((in_le32(&dma->status) & (RUN|ACTIVE)) == RUN)			return 1;		/* That's a bit ugly and dangerous, but works in our case		 * to workaround a problem with the channel status staying		 * active if the drive returns an error		 */		if (IDE_CONTROL_REG) {			byte stat;			stat = GET_ALTSTAT();			if (stat & ERR_STAT)				return 1;		}		/* In some edge cases, some datas may still be in the dbdma		 * engine fifo, we wait a bit for dbdma to complete		 */		while ((in_le32(&dma->status) & (RUN|ACTIVE)) != RUN) {			if (++i > 100)				return 0;			udelay(1);		}		return 1;		/* 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 */#ifdef CONFIG_PMAC_PBOOKstatic void idepmac_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(0xa0, base+0x60);		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;	}}static void idepmac_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;		spin_unlock_irq(&io_request_lock);	}#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */}static void idepmac_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 and reset the bus */	feature_set(np, FEATURE_IDE0_reset);	feature_clear(np, FEATURE_IDE0_enable);	switch(pmac_ide[i].aapl_bus_id) {	    case 0:		feature_set(np, FEATURE_IDE0_reset);		feature_clear(np, FEATURE_IDE0_enable);		break;	    case 1:		feature_set(np, FEATURE_IDE1_reset);		feature_clear(np, FEATURE_IDE1_enable);		break;	    case 2:		feature_set(np, FEATURE_IDE2_reset);		break;	}}static void idepmac_wake_interface(int i, unsigned long base, int mediabay){	struct device_node* np = pmac_ide[i].node;	if (!mediabay) {		/* Revive IDE disk and controller */		switch(pmac_ide[i].aapl_bus_id) {		    case 0:			feature_set(np, FEATURE_IDE0_reset);			feature_set(np, FEATURE_IOBUS_enable);			mdelay(10);	 		feature_set(np, FEATURE_IDE0_enable);			mdelay(10);			feature_clear(np, FEATURE_IDE0_reset);			break;		    case 1:			feature_set(np, FEATURE_IDE1_reset);			feature_set(np, FEATURE_IOBUS_enable);			mdelay(10);	 		feature_set(np, FEATURE_IDE1_enable);			mdelay(10);			feature_clear(np, FEATURE_IDE1_reset);			break;		    case 2:		    	/* This one exists only for KL, I don't know			   about any enable bit */			feature_set(np, FEATURE_IDE2_reset);			mdelay(10);			feature_clear(np, FEATURE_IDE2_reset);			break;		}	}		/* Reset timings */	pmac_ide_selectproc(&ide_hwifs[i].drives[0]);	mdelay(10);}/* 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 idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when){	int i, ret;	unsigned long base;	unsigned long flags;	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;			ide_drive_t *drive;			int unlock = 0;			if ((base = pmac_ide[i].regbase) == 0)				continue;				hwif = &ide_hwifs[i];			drive = &hwif->drives[0];						if (drive->present) {				/* 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);								}			}			/* Disable irq during sleep */			disable_irq(pmac_ide[i].irq);			if (unlock)				spin_unlock_irq(&io_request_lock);						/* 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;							/* 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;			ide_drive_t *drive;						int j, used_dma;						if ((base = pmac_ide[i].regbase) == 0)				continue;							hwif = &ide_hwifs[i];			drive = &hwif->drives[0];			/* Wait for the drive to come up and set it's DMA */			if (drive->present) {				/* Wait up to 20 seconds */				for (j = 0; j < 200; j++) {					int status;					mdelay(100);					status = inb(base + 0x70);					if (!(status & BUSY_STAT))						break;				}			}						/* We don't have re-configured DMA yet */			used_dma = drive->using_dma;			drive->using_dma = 0;			/* We resume processing on the HW group */			spin_lock_irqsave(&io_request_lock, flags);			enable_irq(pmac_ide[i].irq);			if (drive->present)				HWGROUP(drive)->busy = 0;			spin_unlock_irqrestore(&io_request_lock, flags);						/* Wake the device			 * We could handle the slave here			 */			if (drive->present)				idepmac_wake_device(drive, used_dma);		}		break;	}	return PBOOK_SLEEP_OK;}#endif /* CONFIG_PMAC_PBOOK */

⌨️ 快捷键说明

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