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

📄 ide-pmac.c

📁 Linux环境下java编程的经典书籍
💻 C
📖 第 1 页 / 共 3 页
字号:
static __inline__ unsigned charudma_bits_to_command(unsigned char bits, int high_speed){	if (high_speed) {		if(bits & 0x10)			return XFER_UDMA_4;		if(bits & 0x08)			return XFER_UDMA_3;	}	if(bits & 0x04)		return XFER_UDMA_2;	if(bits & 0x02)		return XFER_UDMA_1;	if(bits & 0x01)		return XFER_UDMA_0;	return 0;}/* Calculate MultiWord DMA timings */static int __pmacpmac_ide_mdma_enable(ide_drive_t *drive, int idx){	byte bits = drive->id->dma_mword & 0x07;	byte feature = dma_bits_to_command(bits);	u32 *timings;	int drive_cycle_time;	struct hd_driveid *id = drive->id;	int ret;	/* Set feature on drive */    	printk(KERN_INFO "%s: Enabling MultiWord 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.b.unit & 0x01)		timings = &pmac_ide[idx].timings[1];	else		timings = &pmac_ide[idx].timings[0];	/* Check if drive provide explicit cycle time */	if ((id->field_valid & 2) && (id->eide_dma_time))		drive_cycle_time = id->eide_dma_time;	else		drive_cycle_time = 0;	/* Calculate controller timings */	set_timings_mdma(pmac_ide[idx].kind, timings, feature, drive_cycle_time);	drive->current_speed = feature;		return 1;}/* Calculate Ultra DMA timings */static int __pmacpmac_ide_udma_enable(ide_drive_t *drive, int idx, int high_speed){	byte bits = drive->id->dma_ultra & 0x1f;	byte feature = udma_bits_to_command(bits, high_speed);	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.b.unit & 0x01)		timings = &pmac_ide[idx].timings[1];	else		timings = &pmac_ide[idx].timings[0];	set_timings_udma(timings, feature);	drive->current_speed = feature;		return 1;}static int __pmacpmac_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 ||		pmac_ide[idx].kind == controller_kl_ata4_80);				if(enable) {		if (ata4 && (drive->media == ide_disk) &&		    (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) {			/* 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;	/* 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:	case ide_dma_write:		if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write))			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] + 				((func == ide_dma_read) ? 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);		OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA,			 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));		/* 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 + -