📄 ata.c
字号:
/*! \file ata.c \brief IDE-ATA hard disk interface driver. */
//*****************************************************************************
//
// File Name : 'ata.c'
// Title : IDE-ATA interface driver for hard disks
// Author : Pascal Stang
// Date : 11/22/2000
// Revised : 4/19/2003
// Version : 0.3
// Target MCU : Atmel AVR Series
// Editor Tabs : 4
//
// NOTE: This code is currently below version 1.0, and therefore is considered
// to be lacking in some functionality or documentation, or may not be fully
// tested. Nonetheless, you can expect most functions to work.
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************
#ifndef WIN32
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/pgmspace.h>
// #include <stdio.h>
#endif
#include "global.h"
#include "timer.h"
#include "rprintf.h"
#include "ata.h"
//#define DEBUG_ATA 1
// global variables
// drive information
typeDriveInfo ataDriveInfo;
void ataInit(void)
{
}
void ataDriveInit(void)
{
u08 i;
unsigned char* buffer = (unsigned char*) SECTOR_BUFFER_ADDR;
// read drive identity
rprintfProgStrM("\r\nScanning IDE interface...\r\n");
// Wait for drive to be ready
ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
// issue identify command
ataWriteByte(ATA_REG_CMDSTATUS1, 0xEC);
// wait for drive to request data transfer
ataStatusWait(ATA_SR_DRQ, ATA_SR_DRQ);
timerPause(200);
// read in the data
ataReadDataBuffer(buffer, 512);
// set local drive info parameters
ataDriveInfo.cylinders = *( ((unsigned int*) buffer) + ATA_IDENT_CYLINDERS );
ataDriveInfo.heads = *( ((unsigned int*) buffer) + ATA_IDENT_HEADS );
ataDriveInfo.sectors = *( ((unsigned int*) buffer) + ATA_IDENT_SECTORS );
ataDriveInfo.LBAsupport = *( ((unsigned int*) buffer) + ATA_IDENT_FIELDVALID );
ataDriveInfo.sizeinsectors = *( (unsigned long*) (buffer + ATA_IDENT_LBASECTORS*2) );
// copy model string
for(i=0; i<40; i+=2)
{
// correct for byte order
ataDriveInfo.model[i ] = buffer[(ATA_IDENT_MODEL*2) + i + 1];
ataDriveInfo.model[i+1] = buffer[(ATA_IDENT_MODEL*2) + i ];
}
// terminate string
ataDriveInfo.model[40] = 0;
// process and print info
if(ataDriveInfo.LBAsupport)
{
// LBA support
rprintf("Drive 0: %dMB ", ataDriveInfo.sizeinsectors/(1000000/512) );
rprintf("LBA mode -- MODEL: ");
}
else
{
// CHS, no LBA support
// calculate drive size
ataDriveInfo.sizeinsectors = (unsigned long) ataDriveInfo.cylinders*
ataDriveInfo.heads*ataDriveInfo.sectors;
rprintf("Drive 0: %dMB ", ataDriveInfo.sizeinsectors/(1000000/512) );
rprintf("CHS mode C=%d H=%d S=%d -- MODEL: ", ataDriveInfo.cylinders, ataDriveInfo.heads, ataDriveInfo.sectors );
}
// print model information
rprintfStr(ataDriveInfo.model); rprintfCRLF();
// initialize local disk parameters
//ataDriveInfo.cylinders = ATA_DISKPARM_CLYS;
//ataDriveInfo.heads = ATA_DISKPARM_HEADS;
//ataDriveInfo.sectors = ATA_DISKPARM_SECTORS;
}
void ataDiskErr(void)
{
unsigned char b;
b = ataReadByte(ATA_REG_ERROR);
rprintfProgStrM("ATA Error: ");
rprintfu08(b);
rprintfCRLF();
}
void ataSetDrivePowerMode(u08 DriveNo, u08 mode, u08 timeout)
{
// select drive
ataDriveSelect(DriveNo);
// Wait for drive to be ready
ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
// set mode
switch(mode)
{
case ATA_DISKMODE_SPINDOWN: ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_SPINDOWN); break;
case ATA_DISKMODE_SPINUP: ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_SPINUP); break;
case ATA_DISKMODE_SETTIMEOUT:
ataWriteByte(ATA_REG_SECCOUNT, timeout);
ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_IDLE_5SU);
break;
case ATA_DISKMODE_SLEEP: ataWriteByte(ATA_REG_CMDSTATUS1, ATA_CMD_SLEEP); break;
default:
break;
}
}
void ataPrintSector( u08 *Buffer)
{
u08 i;
u16 j;
u08 *buf;
u08 s;
buf = Buffer;
// print the low order address indicies
rprintfProgStrM(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0123456789ABCDEF\r\n");
rprintfProgStrM(" ----------------------------------------------- ---- ASCII -----\r\n");
// print the data
for(j=0; j<0x20; j++)
{
// print the high order address index for this line
rprintfu16(j<<4);
rprintfProgStrM(" ");
// print the hex data
for(i=0; i<0x10; i++)
{
rprintfu08(buf[(j<<4)+i]);
rprintfProgStrM(" ");
}
// leave some space
rprintfProgStrM(" ");
// print the ascii data
for(i=0; i<0x10; i++)
{
s = buf[(j<<4)+i];
// make sure character is printable
if(s >= 0x20)
{
rprintfChar(s);
}
else
{
rprintfChar(0x20);
}
}
rprintfCRLF();
}
}
void ataReadDataBuffer(u08 *Buffer, u16 numBytes)
{
unsigned int i;
//sbi(MCUCR, SRW); // enable RAM waitstate
// read data from drive
for (i=0; i<(numBytes/16); i++)
{
// optimize by reading 16 bytes in-line before looping
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL);
*Buffer++ = *((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH);
}
//cbi(MCUCR, SRW); // disable RAM waitstate
}
void ataWriteDataBuffer(u08 *Buffer, u16 numBytes)
{
register unsigned char temp;
unsigned int i;
//sbi(MCUCR, SRW); // enable RAM waitstate
// write data to drive
for (i=0; i<(numBytes/16); i++)
{
// optimize by writing 16 bytes in-line before looping
// keep byte order correct by using temp register
temp = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
temp = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
temp = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
temp = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
temp = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
temp = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
temp = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
temp = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAH) = *Buffer++;
*((volatile unsigned char*) ATA_REG_BASE + ATA_REG_DATAL) = temp;
}
//cbi(MCUCR, SRW); // disable RAM waitstate
}
u08 ataStatusWait(u08 mask, u08 waitStatus)
{
register u08 status;
delay(100);
// wait for desired status
while( ((status = ataReadByte(ATA_REG_CMDSTATUS1)) & mask) == waitStatus );
return status;
}
unsigned char ataReadSectorsCHS( unsigned char Drive,
unsigned char Head,
unsigned int Track,
unsigned char Sector,
unsigned int numsectors,
unsigned char *Buffer)
{
unsigned char temp;
// Wait for drive to be ready
temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
// Prepare parameters...
ataWriteByte(ATA_REG_HDDEVSEL, 0xA0+(Drive ? 0x10:00)+Head); // CHS mode/Drive/Head
ataWriteByte(ATA_REG_CYLHI, Track>>8); // MSB of track
ataWriteByte(ATA_REG_CYLLO, Track); // LSB of track
ataWriteByte(ATA_REG_STARTSEC, Sector); // sector
ataWriteByte(ATA_REG_SECCOUNT, numsectors); // # of sectors
// Issue read sector command...
ataWriteByte(ATA_REG_CMDSTATUS1, 0x21);
// Wait for drive to be ready
temp = ataStatusWait(ATA_SR_BSY, ATA_SR_BSY);
if (temp & ATA_SR_ERR)
{
rprintfProgStrM("RD ERR\r\n");
return 1;
}
// Wait for drive to request data transfer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -