ide-ep93xx.c

来自「一个2.4.21版本的嵌入式linux内核」· C语言 代码 · 共 2,386 行 · 第 1/5 页

C
2,386
字号
		 */
		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 int
ep93xx_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 int
ep93xx_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 int
ep93xx_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 int
ep93xx_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 int
ep93xx_ide_dma_host_on(ide_drive_t *drive)
{
	DPRINTK("%s: ep93xx_ide_dma_host_on\n", drive->name);

	if (drive->using_dma)
		return 0;
	return 1;
}

/*****************************************************************************
 *
 * ep93xx_ide_dma_read()
 *
 * This function sets up a dma read operation.
 *
 ****************************************************************************/
static int
ep93xx_ide_dma_read(ide_drive_t *drive)
{
	u8 lba48 = (drive->addressing == 1) ? 1 : 0;
	struct request *rq = HWGROUP(drive)->rq;
	unsigned int flags, i;
	ide_hwif_t *hwif = HWIF(drive);
	task_ioreg_t command = WIN_NOP;

	DPRINTK("%s: ep93xx_ide_dma_read\n", drive->name);
	DPRINTK("    %ld, %ld\n", HWGROUP(drive)->rq->sector,
		HWGROUP(drive)->rq->nr_sectors);

	/*
	 * Check if we are already transferring on this dma channel.
	 */
	if (hwif->sg_dma_active || drive->waiting_for_dma) {
		DPRINTK("%s: dma_read: dma already active \n", drive->name);
		return 1;
	}

	/*
	 * Compute the array index used for this request.
	 */
	i = drive->name[2] == 'a' ? 0 : 2;

	/*
	 * See if this request matches the most recent request, and that the
	 * most recent request ended in error.
	 */
	if (g_bad && (g_cmd == READ) && (g_drive == drive) &&
	    (g_sector == HWGROUP(drive)->rq->sector) &&
	    (g_nr_sectors == HWGROUP(drive)->rq->nr_sectors)) {
		g_cur_retries++;
		if (g_cur_retries > g_max_retries[i])
			g_max_retries[i]++;
		if (g_cur_retries == RETRIES_PER_TRANSFER) {
			g_bad = 0;
			return 1;
		}
	} else {
		g_cur_retries = 0;
		g_cmd = READ;
		g_drive = drive;
		g_sector = HWGROUP(drive)->rq->sector;
		g_nr_sectors = HWGROUP(drive)->rq->nr_sectors;
	}

	/*
	 * Save information about this transfer.
	 */
	g_xfers[i]++;
	g_sectors[i] += HWGROUP(drive)->rq->nr_sectors;

	/*
	 * Indicate that we're waiting for dma.
	 */
	drive->waiting_for_dma = 1;

	/*
	 * Configure DMA M2M channel flags for a source address hold, h/w
	 * initiated P2M transfer.
	 */
	flags = (SOURCE_HOLD | TRANSFER_MODE_HW_P2M);

	if (drive->current_speed & 0x20) {
		flags |= (WS_IDE_MDMA_READ << WAIT_STATES_SHIFT);

		/*
		 * MDMA data register address.
		 */
		hwif->dma_base = IDEMDMADATAIN - IO_BASE_VIRT + IO_BASE_PHYS;
	} else {
		flags |= (WS_IDE_UDMA_READ << WAIT_STATES_SHIFT);
		/*
		 * UDMA data register address.
		 */
		hwif->dma_base = IDEUDMADATAIN - IO_BASE_VIRT + IO_BASE_PHYS;
	}

	/*
	 * Configure the dma interface for this IDE operation.
	 */
	if (ep93xx_dma_config(hwif->hw.dma, 0, flags, ep93xx_ide_callback,
			      (unsigned int)drive) != 0) {
		DPRINTK("%s: ep93xx_ide_dma_read: ERROR- dma config failed",
				drive->name);
		drive->waiting_for_dma = 0;
		/*
		 * Fail.
		 */
		return 1;
	}

	/*
	 * Build the table of dma-able buffers.
	 */
	if (!(g_prd_count = ide_build_dmatable(drive))) {
		DPRINTK("%s: ep93xx_ide_dma_read: ERROR- failed to build dma table",
			drive->name);
		drive->waiting_for_dma = 0;
		/*
		 * Fail, try PIO instead of DMA
		 */
		return 1;
	}

	/*
	 * Indicate that the scatter gather is active.
	 */
	hwif->sg_dma_active = 1;

	/*
	 * test stuff
	 */
	g_prd_total = g_prd_count;
	g_prd_returned = 0;

	DPRINTK("%d buffers\n", g_prd_total);

	/*
	 * Prepare the dma interface with some buffers from the
	 * dma_table.
	 */
	do {
		/*
		 * Add a buffer to the dma interface.
		 */
		if (ep93xx_dma_add_buffer(hwif->hw.dma, hwif->dma_base,
					  hwif->dmatable_cpu[0],
					  hwif->dmatable_cpu[1], 0,
					  g_prd_count) != 0)
			break;
		hwif->dmatable_cpu += 2;

		/*
		 * Decrement the count of dmatable entries
		 */
		g_prd_count--;
	} while (g_prd_count);

	/*
	 * Nothing further is required if this is not a ide_disk (i.e. an ATAPI
	 * device).
	 */
	if (drive->media != ide_disk)
		return 0;

	/*
	 * Determine the command to be sent to the device.
	 */
	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];
	}

	/*
	 * Send the read command to the device.
	 */
	ide_execute_command(drive, command, &ep93xx_ide_dma_intr, 2*WAIT_CMD,
			    &ep93xx_idedma_timer_expiry);

	/*
	 * initiate the dma transfer.
	 */
	return hwif->ide_dma_begin(drive);
}

/*****************************************************************************
 *
 * ep93xx_ide_dma_first_read()
 *
 * This function handles the very first dma read operation.
 *
 ****************************************************************************/
static int
ep93xx_ide_dma_first_read(ide_drive_t *drive)
{
	ide_hwif_t *hwif = HWIF(drive);

	/*
	 * Switch the hwif to the real read routine.
	 */
	hwif->ide_dma_read = ep93xx_ide_dma_read;

	/*
	 * Register a proc entry for the statistics that we gather.
	 */
#ifdef CONFIG_PROC_FS
	create_proc_info_entry("ide/ep93xx", 0, 0, ep93xx_get_info);
#endif

	/*
	 * Do the actual read.
	 */
	return hwif->ide_dma_read(drive);
}

/*****************************************************************************
 *
 * ep93xx_ide_dma_write()
 *
 * This function sets up a dma write operation.
 *
 ****************************************************************************/
static int
ep93xx_ide_dma_write(ide_drive_t *drive)
{
	u8 lba48 = (drive->addressing == 1) ? 1 : 0;
	struct request *rq = HWGROUP(drive)->rq;
	unsigned int flags, i;
	ide_hwif_t *hwif = HWIF(drive);
	task_ioreg_t command = WIN_NOP;

	DPRINTK("%s: ep93xx_ide_dma_write\n", drive->name);

	/*
	 * Check if we are already transferring on this dma channel.
	 */
	if (hwif->sg_dma_active || drive->waiting_for_dma) {
		DPRINTK("%s: dma_write - dma is already active \n",
			drive->name);
		return 1;
	}

	/*
	 * Compute the array index used for this request.
	 */
	i = drive->name[2] == 'a' ? 1 : 3;

	/*
	 * See if this request matches the most recent request, and that the
	 * most recent request ended in error.
	 */
	if (g_bad && (g_cmd == WRITE) && (g_drive == drive) &&
	    (g_sector == HWGROUP(drive)->rq->sector) &&
	    (g_nr_sectors == HWGROUP(drive)->rq->nr_sectors)) {
		g_cur_retries++;
		if (g_cur_retries > g_max_retries[i])
			g_max_retries[i]++;
		if (g_cur_retries == RETRIES_PER_TRANSFER) {
			g_bad = 0;
			return 1;
		}
	} else {
		g_cur_retries = 0;
		g_cmd = WRITE;
		g_drive = drive;
		g_sector = HWGROUP(drive)->rq->sector;
		g_nr_sectors = HWGROUP(drive)->rq->nr_sectors;
	}

	/*
	 * Save information about this transfer.
	 */
	g_xfers[i]++;
	g_sectors[i] += HWGROUP(drive)->rq->nr_sectors;

	/*
	 * Indicate that we're waiting for dma.
	 */
	drive->waiting_for_dma = 1;

	/*
	 * Configure DMA M2M channel flags for a destination address
	 * hold, h/w initiated M2P transfer.
	 */
	flags = (DESTINATION_HOLD | TRANSFER_MODE_HW_M2P);

	/*
	 * Determine if we need the MDMA or UDMA data register.
	 */
	if (drive->current_speed & 0x20) {
		flags |= (WS_IDE_MDMA_WRITE << WAIT_STATES_SHIFT);

		/*
		 * MDMA data register address.
		 */
		hwif->dma_base = IDEMDMADATAOUT - IO_BASE_VIRT + IO_BASE_PHYS;
	} else {
		flags |= (WS_IDE_UDMA_WRITE << WAIT_STATES_SHIFT);

		/*
		 * UDMA data register address.
		 */
		hwif->dma_base = IDEUDMADATAOUT - IO_BASE_VIRT + IO_BASE_PHYS;
	}

	/*
	 * Configure the dma interface for this IDE operation.
	 */
	if (ep93xx_dma_config(hwif->hw.dma, 0, flags, ep93xx_ide_callback,
			      (unsigned int)drive) != 0) {
		drive->waiting_for_dma = 0;
		return 1;
	}

	/*
	 * Build the table of dma-able buffers.
	 */
	if (!(g_prd_count = ide_build_dmatable(drive))) {
		drive->waiting_for_dma = 0;
		/*
		 * Fail, try PIO instead of DMA
		 */
		return 1;
	}

	/*
	 * Indicate that we're waiting for dma.
	 */
	hwif->sg_dma_active = 1;

	/*
	 * test stuff
	 */
	g_prd_total = g_prd_count;
	g_prd_returned = 0;

	/*
	 * Prepare the dma interface with some buffers from the
	 * dma_table.
	 */
	do {
		/*
		 * Add a buffer to the dma interface.
		 */
		if (ep93xx_dma_add_buffer(hwif->hw.dma,
					  hwif->dmatable_cpu[0],
					  hwif->dma_base,
					  hwif->dmatable_cpu[1], 0,
					  g_prd_count) != 0)
			break;
		hwif->dmatable_cpu += 2;

		/*
		 * Decrement the count of dmatable entries
		 */
		g_prd_count--;
	} while (g_prd_count);

	/*
	 * Nothing further is required if this is not a ide_disk (i.e. an ATAPI
	 * device).
	 */
	if (drive->media != ide_disk)
		return 0;

	/*

⌨️ 快捷键说明

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