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

📄 ide-ep93xx.c

📁 ep9315平台下硬盘驱动的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
				*table++ = cur_addr;				xcount = bcount & 0xffff;				if (xcount == 0x0000) {					/*					 * Most chipsets correctly interpret a					 * length of 0x0000 as 64KB, but at					 * least one (e.g. CS5530)					 * misinterprets it as zero (!).  So					 * here we break the 64KB entry into					 * two 32KB entries instead.					 */					if (count++ >= PRD_ENTRIES) {						printk("%s: DMA table too small\n",						       drive->name);						goto use_pio_instead;					}					*table++ = 0x8000;					*table++ = cur_addr + 0x8000;					xcount = 0x8000;				}				*table++ = xcount;				cur_addr += bcount;				cur_len -= bcount;			}		}		sg++;		i--;	}	if (count) {		*--table |= 0x80000000;		return count;	}	printk("%s: empty DMA table?\n", drive->name);use_pio_instead:	/*	 * Revert to PIO for this request.	 */	HWIF(drive)->sg_dma_active = 0;	return 0;}/***************************************************************************** * * ide_release_dma() * * This function releases the memory allocated for the scatter gather list * and for the dma table, and frees the dma channel. * ****************************************************************************/static voidep93xx_ide_release_dma(ide_hwif_t *hwif){	DPRINTK("%s: ep93xx_ide_release_dma\n", hwif->name);	/*	 * Check if we have a valid dma handle.	 */	if (hwif->hw.dma != 0) {		/*		 * Pause the DMA channel.		 */		ep93xx_dma_pause(hwif->hw.dma, 1, 0);		/*		 * Flush the DMA channel		 */		ep93xx_dma_flush(hwif->hw.dma);	}}/***************************************************************************** * * ep93xx_ide_callback() * * Registered with the ep93xx dma driver and called at the end of the dma * interrupt handler, this function should process the dma buffers. * ****************************************************************************/static voidep93xx_ide_callback(ep93xx_dma_int_t dma_int, ep93xx_dma_dev_t device,                    unsigned int user_data){	ide_drive_t *drive = (ide_drive_t *)user_data;	ide_hwif_t *hwif = HWIF(drive);	unsigned int temp;	DPRINTK("ep93xx_ide_callback %d\n", dma_int);	/*	 * Retrieve from the dma interface as many used buffers as are	 * available.	 */	while (ep93xx_dma_remove_buffer(hwif->hw.dma, &temp) == 0)		g_prd_returned++;	/*	 * Add new buffers if we have any available.	 */	while (g_prd_count) {		/*		 * Check if this is a read or write operation.		 */		if (hwif->sg_dma_direction == PCI_DMA_FROMDEVICE)			/*			 * Set up buffers for a read op.			 */			temp = ep93xx_dma_add_buffer(hwif->hw.dma,						     hwif->dma_base,						     hwif->dmatable_cpu[0],						     hwif->dmatable_cpu[1], 0,						     g_prd_count);		else			/*			 * Set up buffers for a write op.			 */			temp = ep93xx_dma_add_buffer(hwif->hw.dma,						     hwif->dmatable_cpu[0],						     hwif->dma_base,						     hwif->dmatable_cpu[1], 0,						     g_prd_count);		/*		 * Add a buffer to the dma interface.		 */		if (temp != 0)			break;		hwif->dmatable_cpu += 2;		/*		 * Decrement the count of dmatable entries		 */		g_prd_count--;	}	/*	 * See if all of the buffers have been returned.	 */	if (g_prd_returned >= g_prd_total) {		/*		 * See if the IDE device is still requesting data.		 */		if (inl(IDECR) & IDECtrl_DMARQ) {			/*			 * Indicate that an error has occurred during this			 * transfer.			 */			g_bad = 1;			/*			 * Add another word to the DMA to try and satisfy the			 * device's request.			 */			if (hwif->sg_dma_direction == PCI_DMA_FROMDEVICE)				ep93xx_dma_add_buffer(hwif->hw.dma,						      hwif->dma_base,						      virt_to_bus(&g_garbage),						      4, 0, 0);			else				ep93xx_dma_add_buffer(hwif->hw.dma,						      virt_to_bus(&g_garbage),						      hwif->dma_base,						      4, 0, 0);		}	}}/***************************************************************************** * *  ep93xx_dma_timer_expiry() * * *	dma_timer_expiry	-	handle a DMA timeout *	@drive: Drive that timed out * *	An IDE DMA transfer timed out. In the event of an error we ask *	the driver to resolve the problem, if a DMA transfer is still *	in progress we continue to wait (arguably we need to add a *	secondary 'I dont care what the drive thinks' timeout here) *	Finally if we have an interrupt we let it complete the I/O. *	But only one time - we clear expiry and if it's still not *	completed after WAIT_CMD, we error and retry in PIO. *	This can occur if an interrupt is lost or due to hang or bugs. * * ****************************************************************************/static intep93xx_idedma_timer_expiry(ide_drive_t *drive){	ide_hwif_t *hwif = HWIF(drive);	u8 dev_stat	 = hwif->INB(IDE_ALTSTATUS_REG);	u8 irq_stat	 = inl(IDECR) & IDECtrl_INTRQ;	DPRINTK(KERN_WARNING "%s: dma_timer_expiry: dev status == 0x%02x,irq= %d\n",		drive->name, dev_stat, irq_stat);	/*	 * Clear the expiry handler in case we decide to wait more,	 * next time timer expires it is an error	 */	HWGROUP(drive)->expiry = NULL;	/*	 * If the interrupt is asserted, call the handler.	 */	if (irq_stat)		HWGROUP(drive)->handler(drive);	/*	 * Check if the busy bit or the drq bit is set, indicating that	 * a dma transfer is still active, or the IDE interrupt is asserted.	 */	if ( (dev_stat & 0x80) || (dev_stat & 0x08) || irq_stat)		return WAIT_CMD;	/*	 * the device is not busy and the interrupt is not asserted, so check	 * if there's an error.	 */	if (dev_stat & 0x01)	/* ERROR */		return -1;	return 0;	/* Unknown status -- reset the bus */}/***************************************************************************** * * ep93xx_config_ide_device() * * This function sets up the ep93xx ide device for a dma transfer by first * probing to find the best dma mode supported by the device. * * Returns a 0 for success, and a 1 otherwise. * ****************************************************************************/static unsigned intep93xx_config_ide_device(ide_drive_t *drive){	byte transfer = 0;	DPRINTK("%s: ep93xx_config_ide_device\n", drive->name);	/*	 * Determine the best transfer speed supported.	 */	transfer = ide_dma_speed(drive, 2);	/*	 * Do not use MW DMA modes above 0 on ATAPI devices since they excite a	 * chip bug.	 */	if ((drive->media != ide_disk) &&	    ((transfer == XFER_MW_DMA_2) || (transfer == XFER_MW_DMA_1)))		transfer = XFER_MW_DMA_0;	/*	 * Do nothing if a DMA mode is not supported.	 */	if (transfer == 0)		return HWIF(drive)->ide_dma_off(drive);	/*	 * Configure the drive.	 */	if (ide_config_drive_speed(drive, transfer) == 0) {		/*		 * Hold on to this value for use later.		 */		drive->current_speed = transfer;		/*		 * Success, so turn on DMA.		 */		return HWIF(drive)->ide_dma_on(drive);	} else		return HWIF(drive)->ide_dma_off(drive);}/***************************************************************************** * *  ep93xx_set_pio() * *  Configures the ep93xx controller for a PIO mode transfer. * ****************************************************************************/static voidep93xx_set_pio(void){	DPRINTK("ep93xx_set_pio\n");	/*	 * Clear the MDMA and UDMA operation registers.	 */	outl(0, IDEMDMAOP);	outl(0, IDEUDMAOP);	/*	 * Reset the UDMA state machine.	 */	outl(IDEUDMADebug_RWOE | IDEUDMADebug_RWPTR | IDEUDMADebug_RWDR |	     IDEUDMADebug_RROE | IDEUDMADebug_RRPTR | IDEUDMADebug_RRDR,	     IDEUDMADEBUG);	outl(0, IDEUDMADEBUG);	/*	 * Enable PIO mode of operation.	 */	outl(IDECfg_PIO | IDECfg_IDEEN | (4 << IDECfg_MODE_SHIFT) |	     (1 << IDECfg_WST_SHIFT), IDECFG);}/***************************************************************************** * *  ep93xx_rwproc() * *  Initializes the ep93xx IDE controller interface with the transfer type, *  transfer mode, and transfer direction. * ****************************************************************************/static voidep93xx_rwproc(ide_drive_t *drive, int action){	DPRINTK("%s: ep93xx_rwproc\n", drive->name);	/*	 * Configure the IDE controller for the specified transfer mode.	 */	switch (drive->current_speed)	{		/*		 * Configure for an MDMA operation.		 */		case XFER_MW_DMA_0:		case XFER_MW_DMA_1:		case XFER_MW_DMA_2:			outl(((drive->current_speed & 3) << IDECfg_MODE_SHIFT) |			     IDECfg_MDMA | IDECfg_IDEEN, IDECFG);			outl(action ? IDEMDMAOp_RWOP : 0, IDEMDMAOP);			outl(inl(IDEMDMAOP) | IDEMDMAOp_MEN, IDEMDMAOP);			break;		/*		 * Configure for a UDMA operation.		 */		case XFER_UDMA_0:		case XFER_UDMA_1:		case XFER_UDMA_2:		case XFER_UDMA_3:		case XFER_UDMA_4:			outl(((drive->current_speed & 7) << IDECfg_MODE_SHIFT) |			     IDECfg_UDMA | IDECfg_IDEEN, IDECFG);			outl(action ? IDEUDMAOp_RWOP : 0, IDEUDMAOP);			outl(inl(IDEUDMAOP) | IDEUDMAOp_UEN, IDEUDMAOP);			break;		default:			break;	}}/***************************************************************************** * * ep93xx_ide_dma_check() * * This function determines if the device supports dma transfers, and if it * does, then enables dma. * ****************************************************************************/static intep93xx_ide_dma_check(ide_drive_t *drive){	ide_hwif_t * hwif = HWIF(drive);	struct hd_driveid *id = drive->id;	DPRINTK("%s: ep93xx_ide_dma_check\n", drive->name);	if (!id || !(id->capability & 1) || !hwif->autodma) {		/*		 * Disable dma for this drive.		 */		hwif->ide_dma_off_quietly(drive);		return 1;	}	/*	 * Consult the list of known "bad" drives	 */	if (in_drive_list(id, drive_blacklist)) {		printk("%s: Disabling DMA for %s (blacklisted)\n",			   drive->name, id->model);		/*		 * Disable dma for this drive.		 */		hwif->ide_dma_off_quietly(drive);		return 1;	}	/*	 * Check if the drive supports multiword dma or udma modes.	 * If it does, then set the device up for that	 * type of dma transfer, and call ep93xx_ide_dma_on.	 */	return ep93xx_config_ide_device(drive);}/***************************************************************************** * * ep93xx_ide_dma_host_off() * * This function disables dma for the host. * ****************************************************************************/static intep93xx_ide_dma_host_off(ide_drive_t *drive){	ide_hwif_t *hwif = HWIF(drive);	/*	 * TODO: what's to be done here?	 */	DPRINTK("%s: ep93xx_ide_dma_host_off\n", drive->name);	/*	 * Release the dma channel and all memory allocated for dma	 * purposes.	 */	ep93xx_ide_release_dma(hwif);	/*	 * Success.	 */	return 0;}/***************************************************************************** * * ep93xx_ide_dma_off_quietly() * * This function, without announcing it,  disables dma for the device. * ****************************************************************************/static intep93xx_ide_dma_off_quietly(ide_drive_t *drive){	DPRINTK("%s: ep93xx_ide_dma_off_quietly\n", drive->name);	/*	 * Clear the using_dma field to indicate that dma is disabled	 * for this drive.	 */	drive->using_dma = 0;	/*	 * Disable dma on the host side.	 */	return HWIF(drive)->ide_dma_host_off(drive);}/***************************************************************************** * * ep93xx_ide_dma_off() * * This function disables dma for the device. * ****************************************************************************/static intep93xx_ide_dma_off(ide_drive_t *drive){	DPRINTK("%s: ep93xx_ide_dma_off\n", drive->name);	return HWIF(drive)->ide_dma_off_quietly(drive);}/***************************************************************************** * * ep93xx_ide_dma_on() * * This function enables dma for the device. * ****************************************************************************/static intep93xx_ide_dma_on(ide_drive_t *drive){	DPRINTK("%s: ep93xx_ide_dma_on\n", drive->name);	/*	 * Set the using_dma field to indicate that dma is enabled.	 */	drive->using_dma = 1;	/*	 * Enable DMA on the host side.	 */	return HWIF(drive)->ide_dma_host_on(drive);}/***************************************************************************** * * ep93xx_ide_dma_host_on() * * This function enables dma for the device. * ****************************************************************************/static intep93xx_ide_dma_host_on(ide_drive_t *drive){	DPRINTK("%s: ep93xx_ide_dma_host_on\n", drive->name);	if (drive->using_dma)

⌨️ 快捷键说明

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