📄 temp.c
字号:
/* high nybble */
DrvHd=(DrvHd & 0x0F) | 0x40;/* b6 enables LBA */
PRINT_DEBUG(printf("ataCmd2: LBA=%lu\n", Temp);)
}
else
{
Sect=Temp % Drive[Cmd->Dev].Sects + 1;
Temp /= Drive[Cmd->Dev].Sects;
DrvHd=Temp % Drive[Cmd->Dev].Heads;
Cyl=Temp / Drive[Cmd->Dev].Heads;
PRINT_DEBUG(printf("ataCmd2: CHS=%u:%u:%u\n", Cyl, DrvHd, Sect);)
}
DrvHd |= Drive[Cmd->Dev].DrvSel;
PRINT_DEBUG(printf("ataCmd2: writing register file\n");)
outp(IOAdr + ATA_REG_CNT, Count);
outp(IOAdr + ATA_REG_SECT, Sect);
outp(IOAdr + ATA_REG_LOCYL, Cyl);
Cyl >>= 8; /* compiler bug work-around */
outp(IOAdr + ATA_REG_HICYL, Cyl);
// >> 8);
outp(IOAdr + ATA_REG_DRVHD, DrvHd);
InterruptOccured=0;
outp(IOAdr + ATA_REG_CMD, CmdByte);
nsleep(400);
}
/*****************************************************************************
name: ataCmd
action: ATA hard drive block read/write
returns: 0 if OK
-1 if drive could not be selected
-2 if unsupported command
-3 if command timed out
-4 if bad/questionable drive status after command
*****************************************************************************/
int ataCmd(drivecmd *Cmd)
{
u8 Stat, CmdByte;
u32 Count, Temp;
u16 IOAdr;
IOAdr=Drive[Cmd->Dev].IOAdr;
/* select the drive */
if(ataSelect(IOAdr, Drive[Cmd->Dev].DrvSel))
{
printf("ataCmd: could not select drive\n");
return(-1);
}
if(Cmd->Cmd == DRV_CMD_RD)
/* convert general block device command code into ATA command byte:ATA_CMD_RDMUL if drive supports multi-sector reads, ATA_CMD_RD if not */
{
if(Drive[Cmd->Dev].MultSect < 2)
CmdByte=ATA_CMD_RD;
else
CmdByte=ATA_CMD_RDMUL;
while(Cmd->Count)
/* if drive supports multisector read/write, transfer as many sectors aspossible (fewer interrupts). We rely on MultSect to limit Temp (thesector count) to < 256 */
{
Temp=(Cmd->Count + ATA_SECTSIZE - 1) >> ATA_LG_SECTSIZE;
Count=min(Temp, Drive[Cmd->Dev].MultSect);
PRINT_DEBUG(printf("ataCmd: ready to read %lu "
"sector(s) of %lu\n", Count, Temp);)
/* compute CHS or LBA register values and write them, along with CmdByte */
ataCmd2(Cmd, Count, CmdByte);/* await read interrupt */
if(awaitInterrupt(0xC000, WAIT_CMD) == 0)
{
printf("ataCmd: read timed out\n");
(void)inp(IOAdr + ATA_REG_STAT);
return(-3);
}
/* check status */
Stat=inp(IOAdr + ATA_REG_STAT);
if((Stat & (0x81 | 0x58)) != 0x58)
{
printf("ataCmd: bad status (0x%02X) "
"during read\n", Stat);
return(-4);
}
/* advance pointers, read data */
Cmd->Blk += Count;
Count <<= ATA_LG_SECTSIZE;
insw(IOAdr + ATA_REG_DATA, (u16 *)Cmd->Data, Count >> 1);
Cmd->Data += Count;
/* XXX - Cmd->Count had better be a multiple of 512... */
Cmd->Count -= Count;
}
return(0);
}
else
if(Cmd->Cmd == DRV_CMD_WR)
/* convert general block device command code into ATA command byte:ATA_CMD_WRMUL if drive supports multi-sector reads, ATA_CMD_WR if not */
{
if(Drive[Cmd->Dev].MultSect < 2)
CmdByte=ATA_CMD_WR;
else
CmdByte=ATA_CMD_WRMUL;
while(Cmd->Count)
/* if drive supports multisector read/write, transfer as many sectors aspossible (fewer interrupts). We rely on MultSect to limit Count(the sector count) to < 256 */
{
Temp=(Cmd->Count + ATA_SECTSIZE - 1) >> ATA_LG_SECTSIZE;
Count=min(Temp, Drive[Cmd->Dev].MultSect);
PRINT_DEBUG(printf("ataCmd: ready to write %lu "
"sector(s) of %lu\n", Count, Temp);)
/* compute CHS or LBA register values and write them, along with CmdByte */
ataCmd2(Cmd, Count, CmdByte);
/* await DRQ */
for(Temp=WAIT_DRQ; Temp; Temp--)
{
if(inp(IOAdr + ATA_REG_ALTST) & 0x08) break;
msleep(1);
}
/* XXX - blocking delay */
if(Temp == 0)
{
printf("ataCmd: no DRQ during write\n");
(void)inp(IOAdr + ATA_REG_STAT);
return(-3);
}
/* advance pointer, write data */
Cmd->Blk += Count;
Count <<= ATA_LG_SECTSIZE;
outsw(IOAdr + ATA_REG_DATA, (u16 *)Cmd->Data, Count >> 1);
/* await write interrupt */
Temp=awaitInterrupt(0xC000, WAIT_CMD);
if(Temp == 0)
{
printf("ataCmd: write timed out\n");
(void)inp(IOAdr + ATA_REG_STAT);
return(-3);
}
/* check status */
Stat=inp(IOAdr + ATA_REG_STAT);
if((Stat & (0xA1 | 0x50)) != 0x50)
{
printf("ataCmd: bad status (0x%02X) during "
"write\n", Stat);
return(-4);
}
/* advance pointers */
Cmd->Data += Count;
/* XXX - Cmd->Count had better be a multiple of 512... */
Cmd->Count -= Count;
}
return(0);
}
else
{
printf("ataCmd: bad cmd (%u)\n", Cmd->Cmd);
return(-2);
}
}
/*
////////////////////////////////////////////////////////////////////////////
ATAPI-ONLY STUFF
////////////////////////////////////////////////////////////////////////////
*/
/* ATAPI packet command bytes */
#define ATAPI_CMD_START_STOP 0x1B /* eject/load */
#define ATAPI_CMD_READ10 0x28 /* read data sector(s) */
#define ATAPI_CMD_READTOC 0x43 /* read audio table-of-contents */
#define ATAPI_CMD_PLAY 0x47 /* play audio */
#define ATAPI_CMD_PAUSE 0x4B /* pause/continue audio */
/* ATAPI data/command transfer 'phases' */
#define ATAPI_PH_ABORT 0 /* other possible phases (1, 2, */
#define ATAPI_PH_DONE 3 /* and 11) are invalid */
#define ATAPI_PH_DATAOUT 8
#define ATAPI_PH_CMDOUT 9
#define ATAPI_PH_DATAIN 10
typedef struct /* 4 bytes */
{
u8 Res0, Min, Sec, Frame;
} atapimsf;
typedef struct /* 4 bytes */
{
u16 TocLen;
u8 FirstTrk;
u8 LastTrk;
} atapitocheader;
typedef struct /* 8 bytes */
{
u8 Res0;
/* In Linux ide.h, the next field was 'unsigned control : 4'I thought "hey, unsigned is 32 bits under GNU"... and that ledto great confusion. The size of this structure _IS_ 8 bytes. */
u8 Ctrl : 4;
u8 Adr : 4;
u8 Trk;
u8 Res1;
union {
u32 Block;
atapimsf Time;
} Where;
} atapitocentry;
typedef struct
{
atapitocheader Hdr;
atapitocentry Ent[100];
} atapitoc;
/*****************************************************************************
name: atapiCmd2
action: writes ATA register file including packet command byte,
busy-waits until drive ready, then writes 12-byte ATAPI
command packet, and services interrupts
returns:0 if success
-1 if drive could not be selected
-3 timeout after writing pkt cmd byte (0xA0)
-4 timeout after writing cmd pkt
-5 data shortage (premature ATAPI_PH_DONE)
-6 drive aborted command
-7 bad drive phase
*****************************************************************************/
/* ATA_REG_STAT & 0x08 (DRQ)
ATA_REG_REASON "phase" 0 0
ATAPI_PH_ABORT 0 1
bad 0 2
bad 0 3
ATAPI_PH_DONE 8 0
ATAPI_PH_DATAOUT 8 1
ATAPI_PH_CMDOUT 8 2
ATAPI_PH_DATAIN 8 3
badb0 of ATA_REG_REASON is C/nD (0=data, 1=command)b1 of ATA_REG_REASON is IO (0=out to drive, 1=in from drive) */
int atapiCmd2(drivecmd *Cmd, u8 *Pkt)
{
u16 IOAdr, Got;
u8 Phase;
u32 Temp;
IOAdr=Drive[Cmd->Dev].IOAdr;
if(ataSelect(IOAdr, Drive[Cmd->Dev].DrvSel))
{
printf("atapiCmd2: could not select drive\n");
return(-1);
}
PRINT_DEBUG(printf("atapiCmd2: writing register file\n");)
outp(IOAdr + ATA_REG_FEAT, 0);
/* irrelevant? */
outp(IOAdr + ATA_REG_REASON, 0);
/* irrelevant? */
outp(IOAdr + ATA_REG_SECT, 0);
/* irrelevant? */
outp(IOAdr + ATA_REG_LOCNT, 32768ul);
outp(IOAdr + ATA_REG_HICNT, 32768ul >> 8);
outp(IOAdr + ATA_REG_CMD, ATA_CMD_PKT);
nsleep(400);
for(Temp=500; Temp; Temp--)
/* XXX - why 500? */
{
if((inp(IOAdr + ATA_REG_STAT) & 0x88) == 0x08) break;
msleep(1);
}
/* this _must_ be polled, I guess */
if(Temp == 0)
{
printf("atapiCmd2: drive did not accept pkt cmd byte\n");
return(-3);
}
InterruptOccured=0;
outsw(IOAdr + ATA_REG_DATA, (u16 *)Pkt, 6);
while(1)
{
if(awaitInterrupt(0xC000, WAIT_CMD) == 0)
{
(void)inp(IOAdr + ATA_REG_STAT);
printf("atapiCmd2: pkt cmd timed out\n");
return(-4);
}
Phase=inp(IOAdr + ATA_REG_STAT) & 0x08;
Phase |= (inp(IOAdr + ATA_REG_REASON) & 3);
if(Phase == ATAPI_PH_DONE)
{
if(Cmd->Count)
{
printf("atapiCmd2: data shortage\n");/* could mean no CD or audio CD */
return(-5);
}
return(0);
}
else
if(Phase == ATAPI_PH_ABORT)
{
printf("atapiCmd2: cmd aborted\n");
return(-6);
}
else
if(Phase != ATAPI_PH_DATAIN)/* ATAPI_PH_DATAOUT or ATAPI_PH_CMDOUT or something completely bogus */
{
printf("atapiCmd2: bad phase %u\n", Phase);
return(-7);
}
Got=inp(IOAdr + ATA_REG_HICNT);
Got=(Got << 8) | inp(IOAdr + ATA_REG_LOCNT);
PRINT_DEBUG(printf("<%5u bytes> ", Got);)
/* Cmd->Count=how many bytes we want to transferGot=how many bytes are available for transferTemp=smaller of these two */
Temp=min(Cmd->Count, Got);
/* read data. XXX - what if Temp odd?XXX - allow read from middle of one sector to middle of another? */
insw(IOAdr + ATA_REG_DATA, (u16 *)Cmd->Data, Temp >> 1);
/* read and discard surplus data */
for(Got -= Temp; Got > 1; Got -= 2)
inpw(IOAdr + ATA_REG_DATA);
if(Got) inp(IOAdr + ATA_REG_DATA);
/* advance pointers */
Cmd->Data += Temp;
Cmd->Count -= Temp;
Temp >>= ATAPI_LG_SECTSIZE;
Cmd->Blk += Temp;
}
}
/*****************************************************************************
name: atapiCmd
action: ATAPI device block read (and later, write)
returns:0 if success (OK)
-1 if drive could not be selected
-2 if unsupported command
-3 timeout after writing pkt cmd byte (0xA0)
-4 timeout after writing cmd pkt
-5 data shortage (premature ATAPI_PH_DONE)
-6 drive aborted command
-7 bad drive phase
*****************************************************************************/
int atapiCmd(drivecmd *Cmd)
{
u8 Pkt[12];
u32 Count;
/* convert general block device command code into ATAPI packet commands */
if(Cmd->Cmd == DRV_CMD_RD)
Pkt[0]=ATAPI_CMD_READ10;
else
{
printf("atapiCmd: bad cmd\n");
return(-2);
}
Pkt[1]=0;
Pkt[2]=Cmd->Blk >> 24;
Pkt[3]=Cmd->Blk >> 16;
Pkt[4]=Cmd->Blk >> 8;
Pkt[5]=Cmd->Blk;
Count=Cmd->Count >> ATAPI_LG_SECTSIZE;
Pkt[6]=Count >> 16;
Pkt[7]=Count >> 8;
Pkt[8]=Count;
Pkt[9]=Pkt[10]=Pkt[11]=0;
return(atapiCmd2(Cmd, Pkt));
}
/*****************************************************************************
name: atapiEject
action: loads (Load == 0) or ejects (Load != 0) CD-ROM
returns:whatever atapiCmd2() returns
*****************************************************************************/
int atapiEject(unsigned Load, unsigned WhichDrive)
{
char Pkt[12]={
ATAPI_CMD_START_STOP,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0 };
drivecmd Cmd;
PRINT_DEBUG(printf("atapiEject\n");)
Cmd.Blk=0;
Cmd.Count=0;
Cmd.Dev=WhichDrive;
Cmd.Cmd=0;
Cmd.Data=NULL;
Pkt[4]=2 + (Load != 0);
return(atapiCmd2(&Cmd, Pkt));
}
/*****************************************************************************
name: atapiPlay
action: plays audio from time index Start to End (units of 1/75 sec)
returns:whatever atapiCmd2() returns
*****************************************************************************/
int atapiPlay(unsigned WhichDrive, u32 Start, u32 End)
{
char Pkt[12]={
ATAPI_CMD_PLAY,
0, 0,
0, 0, 0, /* starting minute:second:frame */
0, 0, 0, /* ending M:S:F (frame=1/75 sec) */
0, 0, 0 };
drivecmd Cmd;
PRINT_DEBUG(printf("atapiPlay\n");)
Cmd.Blk=0;
Cmd.Count=0;
Cmd.Dev=WhichDrive;
Cmd.Cmd=0;
Cmd.Data=NULL;
Pkt[5]=Start % 75;
Start /= 75;
Pkt[4]=Start % 60;
Start /= 60;
Pkt[3]=Start;
Pkt[8]=End % 75;
End /= 75;
Pkt[7]=End % 60;
End /= 60;
Pkt[6]=End;
return(atapiCmd2(&Cmd, Pkt));
}
/*****************************************************************************
name: atapiTOCEnt
action: reads one or more table-of-contents entries from audio CD
returns:whatever atapiCmd2() returns
*****************************************************************************/
int atapiTOCEnt(atapitoc *Contents, unsigned Count, unsigned WhichDrive)
{
char Pkt[12]={
ATAPI_CMD_READTOC,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0 };
drivecmd Cmd;
PRINT_DEBUG(printf("atapiTOCEnt\n");)
Cmd.Blk=0;
Cmd.Count=Count;
Cmd.Dev=WhichDrive;
Cmd.Cmd=0;
Cmd.Data=(u8 *)Contents;
Pkt[1]=2;
Pkt[6]=0;
Pkt[7]=Count >> 8;
Pkt[8]=Count;
Pkt[9]=0;
return(atapiCmd2(&Cmd, Pkt));
}
/*****************************************************************************
name: atapiTOC
action: reads table of contents of audio CD and prints starting
time of each track
returns:whatever atapiCmd2() returns
*****************************************************************************/
#define MAX_TRACKS 32
atapimsf Track[MAX_TRACKS];
unsigned NumTracks;
int atapiTOC(unsigned WhichDrive)
{
atapitoc Contents;
int Temp;/* read just the header at first */
Temp=sizeof(atapitocheader);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -