?? ideutils.c
字號:
/**********************************************
Utilities for IDE
This file is an example of IDE functionality.
Hardware resources required:
1 system timer
1 memory-mapped IDE port, with interrupt.
**********************************************/
#include "system.h"
#include "altera_avalon_timer.h"
#include "altera_avalon_cf_regs.h"
#ifndef CF_IDE_BASE
#error This IDE utility requires a CompactFlash Interface component named "cf"
#endif
#if ALT_SYS_CLK_BASE == none_BASE
#error This IDE utility requires a system clock with millisecond frequency
#endif
#include "sys/alt_alarm.h"
#include "sys/alt_irq.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "ideutils.h"
#define DEBUG 0
#define DEBUGPRINT 0
#define IDEUTILS_printf(x) printf##x
#define getTime() alt_nticks()
#define ctl_base (int*)CF_CTL_BASE
#define ctl_irq (int)CF_CTL_IRQ
#define ide_base (int*)CF_IDE_BASE
#define ide_irq (int)CF_IDE_IRQ
// Exactly one IDE drive is assumed: these globals store parameters
// of that drive.
unsigned short gusLogicalHeads = 0,
gusLogicalCylinders = 0,
gusSectorsPerTrack = 0;
unsigned short gusPIOmode = 0;
unsigned short gusLBAmode = 0;
unsigned long gulLBAcapacity = 0;
unsigned char gModel[40+1];
volatile int IDEinterrupt = 0;
volatile int giMediaChanged = 0;
int gbVerbose = 1;
int IDE_getVerbosity(void)
{
return gbVerbose;
}
void IDE_setVerbosity(int iVerbosity)
{
gbVerbose = iVerbosity;
}
// controller interrupt routines
void IDETrapHandler(void* context, alt_u32 id)
{
IORD_ALTERA_AVALON_CF_IDE_STATUS(ide_base); // (To clear INTRQ)
IDEinterrupt = 1;
}
void CTLTrapHandler(void* context, alt_u32 id)
{
giMediaChanged = 1;
if (IORD_ALTERA_AVALON_CF_CTL_STATUS(ctl_base)
& ALTERA_AVALON_CF_CTL_STATUS_PRESENT_MSK)
{
//printf("CompactFlash inserted\n");
}
else
{
//printf("CompactFlash removed\n");
}
}
int MediaChanged(void)
{
if (giMediaChanged)
{
giMediaChanged = 0;
return 1;
}
return 0;
}
// timed functions
int awaitBSYZeroOrINTRQ(int iMS)
{
unsigned int uiSuccess;
unsigned int uiStartTime;
volatile unsigned int uiDeltaTime;
uiSuccess = 0;
uiStartTime = getTime();
do
{
if (0 ==
(IORD_ALTERA_AVALON_CF_IDE_ALTERNATE_STATUS(ide_base) & AltStatusRegBitBSY))
{
uiSuccess = 1;
break;
}
if (IDEinterrupt == 1)
{
IDEinterrupt = 0;
uiSuccess = 1;
break;
}
uiDeltaTime = getTime() - uiStartTime;
} while (uiDeltaTime < iMS);
return uiSuccess;
}
int awaitDRQ(int iMS)
{
unsigned int uiSuccess;
volatile unsigned int uiStartTime, uiDeltaTime;
unsigned short usStatus;
uiSuccess = 0;
uiStartTime = getTime();
while ((uiDeltaTime = getTime() - uiStartTime) < iMS)
{
usStatus = IORD_ALTERA_AVALON_CF_IDE_ALTERNATE_STATUS(ide_base);
// i) If DRQ=1, the host transfers a block of data by reading the Data register.
// If any error conditions are present in the status read in step h), the
// data transfer may not be valid.
if (usStatus & AltStatusRegBitDRQ)
{
uiSuccess = 1;
break;
}
}
if (!uiSuccess)
{
printf("timeout awaiting DRQ=1\r");
printf("error register: 0x%X\r", IORD_ALTERA_AVALON_CF_IDE_ERROR(ide_base));
return 0;
}
#if DEBUG
printf("DRQ found after %d ms\r", uiDeltaTime);
#endif // DEBUG
return uiSuccess;
}
int awaitINTRQ(int iMS)
{
unsigned int uiSuccess;
volatile unsigned int uiStartTime, uiDeltaTime;
uiSuccess = 0;
uiStartTime = getTime();
while ((uiDeltaTime = getTime() - uiStartTime) < iMS)
{
if (IDEinterrupt == 1)
{
IDEinterrupt = 0;
uiSuccess = 1;
break;
}
}
if (!uiSuccess)
{
printf("timeout awaiting INTRQ=1\r");
printf("error register: 0x%X\r", IORD_ALTERA_AVALON_CF_IDE_ERROR(ide_base));
return 0;
}
#if DEBUG
printf("INTRQ found after %d ms\r", uiDeltaTime);
#endif // DEBUG
return uiSuccess;
}
int awaitBSYZero(unsigned int uiTimeout)
{
unsigned int uiSuccess;
unsigned int uiStartTime;
volatile unsigned int uiDeltaTime;
uiSuccess = 0;
uiStartTime = getTime();
do
{
if (0 ==
(IORD_ALTERA_AVALON_CF_IDE_ALTERNATE_STATUS(ide_base) & AltStatusRegBitBSY))
{
uiSuccess = 1;
break;
}
uiDeltaTime = getTime() - uiStartTime;
} while (uiDeltaTime < uiTimeout);
return uiSuccess;
}
int awaitBSYOne(unsigned int uiTimeout)
{
unsigned int uiSuccess;
volatile unsigned int uiStartTime, uiDeltaTime;
uiSuccess = 0;
uiStartTime = getTime();
while ((uiDeltaTime = getTime() - uiStartTime) < uiTimeout)
{
if (1 == !!(IORD_ALTERA_AVALON_CF_IDE_ALTERNATE_STATUS(ide_base) & AltStatusRegBitBSY))
{
uiSuccess = 1;
break;
}
}
return uiSuccess;
}
int awaitBSYZeroDRDYOne(void)
{
unsigned short r;
unsigned int uiSuccess;
volatile unsigned int uiStartTime, uiDeltaTime;
uiSuccess = 0;
uiStartTime = getTime();
while ((uiDeltaTime = getTime() - uiStartTime) < 10)
{
r = IORD_ALTERA_AVALON_CF_IDE_ALTERNATE_STATUS(ide_base);
if ((r & (AltStatusRegBitBSY | AltStatusRegBitDRDY)) ==
AltStatusRegBitDRDY)
{
uiSuccess = 1;
break;
}
}
if (!uiSuccess)
{
return 0;
}
return uiSuccess;
}
// Wrapper functions for IDE commands.
int softwareReset(unsigned int uiDeviceNumber)
{
volatile unsigned int uiStartTime;
unsigned int uiSuccess;
// Select the device to reset.
if (uiDeviceNumber > 1)
{
printf("invalid device number in softwareReset (%d)\n",
uiDeviceNumber);
return 0;
}
IOWR_ALTERA_AVALON_CF_IDE_DEVICE_HEAD(ide_base, uiDeviceNumber ? DevHeadRegBitDEV : 0);
// Host sets the SRST bit to 1 in the Device Control register.
// (Note: interrupt is enabled.)
IOWR_ALTERA_AVALON_CF_IDE_DEVICE_CONTROL(ide_base, (DevControlRegBitSRST | DevControlRegBitNIEN));
// Device 0 sets BSY bit no later than 400ns after detection of SRST=1
// (I give it ~10ms.)
if (!awaitBSYOne(100))
{
printf("timeout awaiting BSY=1 in softwareReset()\n");
return 0;
}
#if DEBUG
else
{
printf("found BSY=1\n");
}
#endif // DEBUG
// Device 0 performs hardware init and diag
// Dev0 may revert to its default condition
// Dev0 posts diag results to the Error Register
// Hm. How am I supposed to know when the diag results have arrived?
// There seems to be no handshaking, so I'll assume I can set SRST=0 any
// old time.
// Dev0 waits for the host to set SRST=0.
IOWR_ALTERA_AVALON_CF_IDE_DEVICE_CONTROL(ide_base, DevControlRegBitNIEN);
// (If a device 1 is expected, some lengthy drive-to-drive communication may occur)
// If no device was detected previously, bit 7 of Error Register set to 0.
// The device sets
// Sector Count to 01,
// Sector Number to 01,
// Cylinder Low register to 0,
// Cylinder High register to 0,
// Device/Head register to 0.
// Device 0 clears the BSY bit when ready to accept commands that do not require
// DRDY to be 1 (no later than 31 seconds from the time that the host sets SRST=0).
// (watch for the BSY=0)
if (!awaitBSYZero(1000))
{
printf("timeout awaiting BSY=0 in softwareReset()\n");
return 0;
}
#if DEBUG
printf("found BSY=0\n");
#endif // DEBUG
// Device 0 sets DRDY when ready to accept any command.
uiSuccess = 0;
uiStartTime = getTime();
while (getTime() - uiStartTime < 1000)
{
if (IORD_ALTERA_AVALON_CF_IDE_ALTERNATE_STATUS(ide_base) & AltStatusRegBitDRDY)
{
uiSuccess = 1;
break;
}
}
if (!uiSuccess)
{
printf("timeout awaiting DRDY=1 in softwareReset()\n");
return 0;
}
#if DEBUG
// printf("found DRDY=1 after %d ms\r", uiDeltaTime);
#endif // DEBUG
#if DEBUG
// Verify sector count = 1,
// sector number = 1,
// cylinder low = 0,
// cylinder high = 0,
// dev/head reg = 0.
printf("status register: 0x%X\r", IORD_ALTERA_AVALON_CF_IDE_STATUS(ide_base));
printf("sector count: 0x%X\r", IORD_ALTERA_AVALON_CF_IDE_SECTOR_COUNT(ide_base));
printf("sector number: 0x%X\r", IORD_ALTERA_AVALON_CF_IDE_SECTOR_NUMBER(ide_base));
printf("cylinder low: 0x%X\r", IORD_ALTERA_AVALON_CF_IDE_CYLINDER_LOW(ide_base));
printf("cylinder high: 0x%X\r", IORD_ALTERA_AVALON_CF_IDE_CYLINDER_HIGH(ide_base));
printf("device/head: 0x%X\r", IORD_ALTERA_AVALON_CF_IDE_DEVICE_HEAD(ide_base));
#else // !DEBUG
if (
(0xFF & IORD_ALTERA_AVALON_CF_IDE_STATUS(ide_base)) != 0x50 ||
(0xFF & IORD_ALTERA_AVALON_CF_IDE_SECTOR_COUNT(ide_base)) != 1 ||
(0xFF & IORD_ALTERA_AVALON_CF_IDE_SECTOR_NUMBER(ide_base)) != 1 ||
(0xFF & IORD_ALTERA_AVALON_CF_IDE_CYLINDER_LOW(ide_base)) != 0 ||
(0xFF & IORD_ALTERA_AVALON_CF_IDE_CYLINDER_HIGH(ide_base)) != 0 ||
(0xFF & IORD_ALTERA_AVALON_CF_IDE_DEVICE_HEAD(ide_base)) != 0)
{
printf("software reset command failed.\r");
}
else
{
printf("software reset command succeeded.\r");
}
#endif // DEBUG
return 1;
}
int PIODataInOrOutPreamble(int iDevice)
{
// Select the device to identify.
if (iDevice > 1)
{
printf("invalid device number in PIODataInOrOut(%d)\r",
iDevice);
return 0;
}
// a) The host reads the status or alt status reg until BSY=0.
if (!awaitBSYZero(1000))
{
printf("timeout (1) awaiting BSY=0 in PIODataInOrOut()\r");
return 0;
}
// b) The host writes the dev/head register with the appropriate dev
// bit value.
IOWR_ALTERA_AVALON_CF_IDE_DEVICE_HEAD(ide_base, iDevice ? DevHeadRegBitDEV : 0);
// c) The host reads the status or alt status register until BSY=0 and
// DRDY=1.
if (!awaitBSYZeroDRDYOne())
{
printf("timeout awaiting BSY=0, DRDY=1 in PIODataInOrOut()\r");
return 0;
}
return 1;
}
// PIO Data In:
// a) The host reads the status or alt status reg until BSY=0.
// b) The host writes the dev/head register with the appropriate dev
// bit value.
// c) The host reads the status or alt status register until BSY=0 and
// DRDY=1.
// d) The host writes any required command parameters to the Features,
// Sector Count, Sector Number, Cylinder High, Cylinder Low and
// Device/Head registers.
// e) The host writes the command code to the Command register.
// f) The device sets the BSY bit and prepares to execute the command
// including preparation to transfer the first block of data to the
// host. (Note: it may take up to 400ns for BSY to go high.)
// g) When the block of data is available, the device sets the DRQ bit
// (setting the DRQ bit is optional if an error condition exists).
// If there is an error condition, the device sets the appropriate status
// and error bits as required by that error condition. Finally, the device
// clears BSY and then asserts INTRQ. (Note: there may be times when BSY
// is set in f) and then cleared in g) so quickly that the host may not
// be able to detect that BSY had been set.)
// h) After detecting either BSY=0 (alt status) or INTRQ, the host reads and
// saves the contents of the status register.
// i) If DRQ=1, the host transfers a block of data by reading the Data register.
// If any error conditions are present in the status read in step h), the
// data transfer may not be valid.
// j) When the status register is read, the device negates INTRQ. In response to
// the complete data block being read, one of the following actions is taken:
// - if no error status was presented to the host in step h), and if transfer
// of another block is required, the device sets BSY and the above sequence
// is repeated starting from step g).
// - If an error status was present in the status read in step h), the device
// clears DRQ and the command execution is complete.
// - If the last block was transfered, the device clears DRQ and the command
// execution is complete.
int readSectorsCHSResult(int iSectorCount, unsigned short *pusBuffer)
{
unsigned short usStatus;
int iSect;
int i, iIndex;
// f) The device sets the BSY bit and prepares to execute the command
// including preparation to transfer the first block of data to the
// host. (Note: it may take up to 400ns for BSY to go high.)
// g) When the block of data is available, the device sets the DRQ bit
// (setting the DRQ bit is optional if an error condition exists).
// If there is an error condition, the device sets the appropriate status
// and error bits as required by that error condition. Finally, the device
// clears BSY and then asserts INTRQ. (Note: there may be times when BSY
// is set in f) and then cleared in g) so quickly that the host may not
// be able to detect that BSY had been set.)
for (iSect = 0; iSect < iSectorCount; ++iSect)
{
if (!awaitDRQ(1000))
{
printf("timeout awaiting DRQ in readSectorsCHS()\r");
}
if (!awaitBSYZero(1000))
{
printf("timeout (2) awaiting BSY=0 in readSectorsCHS()\r");
return 0;
}
if (!awaitINTRQ(5000))
{
printf("timeout awaiting INTRQ=1 in readSectorsCHS()\r");
printf("error register: 0x%X\r", IORD_ALTERA_AVALON_CF_IDE_ERROR(ide_base));
return 0;
}
// h) After detecting either BSY=0 (alt status) or INTRQ, the host reads and
// saves the contents of the status register.
usStatus = IORD_ALTERA_AVALON_CF_IDE_STATUS(ide_base); // (To clear INTRQ)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -