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 + -
显示快捷键?