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

📄 pmac.c

📁 这个linux源代码是很全面的~基本完整了~使用c编译的~由于时间问题我没有亲自测试~但就算用来做参考资料也是非常好的
💻 C
📖 第 1 页 / 共 4 页
字号:
		BUG();	ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);	/*	 * FIX ME to use only ACB ide_task_t args Struct	 */#if 0	{		ide_task_t *args = rq->special;		command = args->tfRegister[IDE_COMMAND_OFFSET];	}#else	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;	if (rq->cmd == IDE_DRIVE_TASKFILE) {		ide_task_t *args = rq->special;		command = args->tfRegister[IDE_COMMAND_OFFSET];	}#endif	/* issue cmd to drive */	hwif->OUTB(command, IDE_COMMAND_REG);	return pmac_ide_dma_begin(drive);}static int __pmacpmac_ide_dma_write (ide_drive_t *drive){	ide_hwif_t *hwif = HWIF(drive);	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;	struct request *rq = HWGROUP(drive)->rq;//	ide_task_t *args = rq->special;	u8 unit = (drive->select.b.unit & 0x01);	u8 ata4;	u8 lba48 = (drive->addressing == 1) ? 1 : 0;	task_ioreg_t command = WIN_NOP;	if (pmif == NULL)		return 1;	ata4 = (pmif->kind == controller_kl_ata4);	if (!pmac_ide_build_dmatable(drive, rq, PCI_DMA_TODEVICE))		/* try PIO instead of DMA */		return 1;	/* Apple adds 60ns to wrDataSetup on reads */	if (ata4 && (pmif->timings[unit] & TR_66_UDMA_EN)) {		writel(pmif->timings[unit],			(unsigned *)(IDE_DATA_REG+IDE_TIMING_CONFIG));		io_flush(readl((unsigned *)(IDE_DATA_REG + IDE_TIMING_CONFIG)));	}	drive->waiting_for_dma = 1;	if (drive->media != ide_disk)		return 0;	/* paranoia check */	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */		BUG();	ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, NULL);	/*	 * FIX ME to use only ACB ide_task_t args Struct	 */#if 0	{		ide_task_t *args = rq->special;		command = args->tfRegister[IDE_COMMAND_OFFSET];	}#else	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;	if (rq->cmd == IDE_DRIVE_TASKFILE) {		ide_task_t *args = rq->special;		command = args->tfRegister[IDE_COMMAND_OFFSET];	}#endif	/* issue cmd to drive */	hwif->OUTB(command, IDE_COMMAND_REG);	return pmac_ide_dma_begin(drive);}static int __pmacpmac_ide_dma_count (ide_drive_t *drive){	return HWIF(drive)->ide_dma_begin(drive);}static int __pmacpmac_ide_dma_begin (ide_drive_t *drive){	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;	volatile struct dbdma_regs *dma;	if (pmif == NULL)		return 1;	dma = pmif->dma_regs;	writel((RUN << 16) | RUN, &dma->control);	/* Make sure it gets to the controller right now */	io_flush(readl(&dma->control));	return 0;}static int __pmacpmac_ide_dma_end (ide_drive_t *drive){	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;	volatile struct dbdma_regs *dma;	u32 dstat;		if (pmif == NULL)		return 0;	dma = pmif->dma_regs;	drive->waiting_for_dma = 0;	dstat = readl(&dma->status);	writel(((RUN|WAKE|DEAD) << 16), &dma->control);	pmac_ide_destroy_dmatable(drive);	/* verify good dma status */	return (dstat & (RUN|DEAD|ACTIVE)) != RUN;}static int __pmacpmac_ide_dma_test_irq (ide_drive_t *drive){	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;	volatile struct dbdma_regs *dma;	unsigned long status;	if (pmif == NULL)		return 0;	dma = pmif->dma_regs;	/* 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.	 */	status = readl(&dma->status);	if (!(status & ACTIVE))		return 1;	if (!drive->waiting_for_dma)		printk(KERN_WARNING "ide%d, ide_dma_test_irq \			called while not waiting\n", HWIF(drive)->index);	/* 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", HWIF(drive)->index);		return 1;	}	udelay(1);	return 0;}static int __pmacpmac_ide_dma_host_off (ide_drive_t *drive){	return 0;}static int __pmacpmac_ide_dma_host_on (ide_drive_t *drive){	return 0;}static int __pmacpmac_ide_dma_lostirq (ide_drive_t *drive){	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;	volatile struct dbdma_regs *dma;	unsigned long status;	if (pmif == NULL)		return 0;	dma = pmif->dma_regs;	status = readl(&dma->status);	printk(KERN_ERR "ide-pmac lost interrupt, dma status: %lx\n", status);	return 0;}static void __init pmac_ide_setup_dma(struct device_node *np, int ix){	struct pmac_ide_hwif *pmif = &pmac_ide[ix];	if (device_is_compatible(np, "kauai-ata")) {		pmif->dma_regs = (volatile struct dbdma_regs*)(pmif->mapbase + 0x1000);	} else {		if (request_OF_resource(np, 1, " (mac-io IDE DMA)") == NULL) {			printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name);			return;		}	}	pmif->dma_regs =		(volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200);	/*	 * Allocate space for the DBDMA commands.	 * The +2 is +1 for the stop command and +1 to allow for	 * aligning the start address to a multiple of 16 bytes.	 */	pmif->dma_table_cpu = (struct dbdma_cmd*)pci_alloc_consistent(		ide_hwifs[ix].pci_dev,		(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),		&pmif->dma_table_dma);	if (pmif->dma_table_cpu == NULL) {		printk(KERN_ERR "%s: unable to allocate DMA command list\n",		       ide_hwifs[ix].name);		return;	}	pmif->sg_table = kmalloc(sizeof(struct scatterlist) * MAX_DCMDS,				 GFP_KERNEL);	if (pmif->sg_table == NULL) {		pci_free_consistent(	ide_hwifs[ix].pci_dev,					(MAX_DCMDS + 2) * sizeof(struct dbdma_cmd),				    	pmif->dma_table_cpu, pmif->dma_table_dma);		return;	}	ide_hwifs[ix].ide_dma_off = &__ide_dma_off;	ide_hwifs[ix].ide_dma_off_quietly = &__ide_dma_off_quietly;	ide_hwifs[ix].ide_dma_on = &__ide_dma_on;	ide_hwifs[ix].ide_dma_check = &pmac_ide_dma_check;	ide_hwifs[ix].ide_dma_read = &pmac_ide_dma_read;	ide_hwifs[ix].ide_dma_write = &pmac_ide_dma_write;	ide_hwifs[ix].ide_dma_count = &pmac_ide_dma_count;	ide_hwifs[ix].ide_dma_begin = &pmac_ide_dma_begin;	ide_hwifs[ix].ide_dma_end = &pmac_ide_dma_end;	ide_hwifs[ix].ide_dma_test_irq = &pmac_ide_dma_test_irq;	ide_hwifs[ix].ide_dma_host_off = &pmac_ide_dma_host_off;	ide_hwifs[ix].ide_dma_host_on = &pmac_ide_dma_host_on;	ide_hwifs[ix].ide_dma_good_drive = &__ide_dma_good_drive;	ide_hwifs[ix].ide_dma_bad_drive = &__ide_dma_bad_drive;	ide_hwifs[ix].ide_dma_verbose = &__ide_dma_verbose;	ide_hwifs[ix].ide_dma_timeout = &__ide_dma_timeout;	ide_hwifs[ix].ide_dma_retune = &__ide_dma_retune;	ide_hwifs[ix].ide_dma_lostirq = &pmac_ide_dma_lostirq;#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO	if (!noautodma)		ide_hwifs[ix].autodma = 1;#endif	ide_hwifs[ix].drives[0].autodma = ide_hwifs[ix].autodma;	ide_hwifs[ix].drives[1].autodma = ide_hwifs[ix].autodma;}#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */static void __pmacidepmac_sleep_device(ide_drive_t *drive){	ide_hwif_t *hwif = HWIF(drive);	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 */		SELECT_DRIVE(drive);		SELECT_MASK(drive, 0);		hwif->OUTB(drive->select.all, IDE_SELECT_REG);		io_flush(hwif->INB(IDE_SELECT_REG));		udelay(100);		hwif->OUTB(0x00, IDE_SECTOR_REG);		hwif->OUTB(0x00, IDE_NSECTOR_REG);		hwif->OUTB(0x00, IDE_LCYL_REG);		hwif->OUTB(0x00, IDE_HCYL_REG);		hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);   		hwif->OUTB(WIN_STANDBYNOW1, IDE_COMMAND_REG);		for (j = 0; j < 10; j++) {			u8 status;			mdelay(100);			status = hwif->INB(IDE_STATUS_REG);			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_dma_check(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(pmac_ide_hwif_t *pmif, unsigned base, int mediabay){	struct device_node* np = pmif->node;	/* We clear the timings */	pmif->timings[0] = 0;	pmif->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, pmif->aapl_bus_id, 0);}static void __pmacidepmac_wake_interface(pmac_ide_hwif_t *pmif, unsigned long base, int mediabay){	struct device_node* np = pmif->node;	if (!mediabay) {		/* Revive IDE disk and controller */		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 1);		ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmif->aapl_bus_id, 1);		mdelay(10);		ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmif->aapl_bus_id, 0);	}}static void __pmacidepmac_sleep_drive(ide_drive_t *drive){	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);	}	if (unlock)		spin_unlock_irq(&io_request_lock);}static void __pmacidepmac_wake_drive(ide_drive_t *drive, unsigned long base){	ide_hwif_t *hwif = HWIF(drive);	unsigned long flags;	int j;		/* Reset timings */	pmac_ide_do_update_timings(drive);	mdelay(10);		/* Wait up to 20 seconds for the drive to be ready */	for (j = 0; j < 200; j++) {		u8 status = 0;		mdelay(100);		hwif->OUTB(drive->select.all, base + 0x60);		if ((hwif->INB(base + 0x60)) != drive->select.all)			continue;		status = hwif->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]);			}			/* 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(&pmac_ide[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(&pmac_ide[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(&pmac_ide[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 */

⌨️ 快捷键说明

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