⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 temp.c

📁 nucleus10版本源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
Fixes/changes:	- CD-ROM now works properly after ATAPI 'identify'.
Bugs/to do:	- Write a new ataXfer() that
* allows reads to start in the middle of an ATA or ATAPI sector
(no odd writes until a buffer cache system is added)
(change Blk field of drivecmd [sectors] to Offset [bytes])
* allows odd-length Count in drivecmd
	- Buffer cache
	- Queued drive operations
	- TEST drives on 2nd interface (0x170, IRQ15).
	- Still some arbitrary timeout values.
	- atapiCmd2() reads only 2048 bytes at a time. Is this normal?
	- False detection of slave ATA drive with Seagate ST3144A master
	(it's jumpered properly, and Linux and the BIOS work OK).
	- Lots of blocking delays. This code is only partially interrupt-	  
	driven, and not yet suitable for a high-performance OS.
	- Code needs more error checking and error-recovery.
*****************************************************************************/
#include	<stdlib.h>	/* srand() rand() */
#include	<conio.h>	/* getch() */
#include	<stdio.h>	/* NULL printf() cprintf() */

//#define DEBUG

#ifdef DEBUG
/* extra debugging messages */
#define	PRINT_DEBUG(X)	X
#else
/* no debug msgs */
#define	PRINT_DEBUG(X)
#endif/*
////////////////////////////////////////////////////////////////////////////
LOW LEVEL FUNCTIONS AND BASIC DEFINTIONS
////////////////////////////////////////////////////////////////////////////
*/
/* delay() inp() inpw() outp() outpw() */
#include	<dos.h>
typedef unsigned char	u8;	/* 8 bits */
typedef unsigned short	u16;	/* 16 bits */
typedef unsigned long	u32;	/* 32 bits */
#define		msleep		delay
#define min(a,b)    (((a) < (b)) ? (a) : (b))

int InterruptOccured;

/*****************************************************************************	
name:	nsleep	
action:	precision delay for Count nanoseconds		
	(not yet implemented)
*****************************************************************************/
void nsleep(unsigned Count)
{
	delay(0);
}

/*****************************************************************************	
name:	insw	
action:	reads Count words (16-bit) from I/O port Adr to		
	memory location Data
*****************************************************************************/
void insw(unsigned Adr, u16 *Data, unsigned Count)
{	
	for(; Count; Count--)		
        	*Data++=inpw(Adr);
}

/*****************************************************************************	
name:	outsw
action:	writes Count words (16-bit) from memory location Data
	to I/O port Adr
*****************************************************************************/
void outsw(unsigned Adr, u16 *Data, unsigned Count)
{
	for(; Count; Count--)
		outpw(Adr, *Data++);
}

/*****************************************************************************
name:	dump
action:	hexadecimal memory dump of Count bytes at Data
*****************************************************************************/
#define		BPERL		16
/* byte/line for dump */
void dump(u8 *Data, unsigned Count)
{
	unsigned Byte1, Byte2;
	while(Count)
	{
		for(Byte1=0; Byte1 < BPERL; Byte1++, Count--)
		{
			if(Count == 0) break;
			printf("%02X ", Data[Byte1]);
		}
		printf("\t");
		for(Byte2=0; Byte2 < Byte1; Byte2++)
			printf("%c", Data[Byte2] < ' ' ? '.' : Data[Byte2]);
		printf("\n");
		Data += BPERL;
	}
}

/*****************************************************************************
name:	awaitInterrupt
action:	waits with Timeout (mS) until interrupt(s) given by bitmask
	IRQMask occur
returns:nonzero Mask value if interrupt occured, zero if timeout
*****************************************************************************/
int awaitInterrupt(u16 IRQMask, unsigned Timeout)
{
	u16 Intr;
	for(; Timeout; Timeout--)
	{
		Intr=InterruptOccured & IRQMask;
		if(Intr) break;
		msleep(1);
	}
	/* XXX - blocking delay - fix */
	if(Timeout == 0) return(0);
	InterruptOccured &= ~Intr;
	return(Intr);
}
/*
////////////////////////////////////////////////////////////////////////////
ATA/ATAPI STUFF
////////////////////////////////////////////////////////////////////////////
*/
/* Delays from Linux ide.h (milliseconds) */
#define	WAIT_READY	30	/* RDY asserted, use 5000 for notebook/APM */
#define	WAIT_ID		30000	/* ATA device responds to 'identify' */
#define	WAIT_PID	3	/* ATAPI device responds to 'identify' */
#define	WAIT_CMD	10000	/* IRQ occurs in response to command */
#define	WAIT_DRQ	20	/* DRQ asserted after ATA_CMD_WR(MUL) */
/* 'Cmd' field of 'drivecmd' structure */
#define	DRV_CMD_RD	1
#define	DRV_CMD_WR	2
/* ATA or ATAPI command structure */
typedef struct{
	u32 Blk;	/* in SECTORS */
	u32 Count;	/* in BYTES */
	u8 Dev, Cmd, *Data;
 } drivecmd;
/* ATA sector size */
#define	ATA_LG_SECTSIZE		9				/* 512 byte ATA drive sectors */
#define	ATA_SECTSIZE		(1 << (ATA_LG_SECTSIZE))	/* ATAPI sector size */
#define	ATAPI_LG_SECTSIZE	11				/* 2K CD-ROM sectors */
#define	ATAPI_SECTSIZE		(1 << (ATAPI_LG_SECTSIZE))
/* ATA drive command bytes */
#define	ATA_CMD_RD	0x20					/* read one sector */
#define	ATA_CMD_WR	0x30					/* write one sector */
#define	ATA_CMD_PKT	0xA0					/* ATAPI packet cmd */
#define	ATA_CMD_PID	0xA1					/* ATAPI identify */
#define	ATA_CMD_RDMUL	0xC4					/* read multiple sectors */
#define	ATA_CMD_WRMUL	0xC5					/* write multiple sectors */
#define	ATA_CMD_ID	0xEC					/* ATA identify */
/* ATA drive flags */
#define	ATA_FLG_ATAPI	0x0001					/* ATAPI drive */
#define ATA_FLG_LBA	0x0002					/* LBA-capable */
#define ATA_FLG_DMA	0x0004					/* DMA-capable */
/* ATA/ATAPI drive register file */
#define	ATA_REG_DATA	0					/* data (16-bit) */
#define	ATA_REG_FEAT	1					/* write: feature reg */
#define	ATA_REG_ERR	ATA_REG_FEAT				/* read: error */
#define	ATA_REG_CNT	2					/* ATA: sector count */
#define	ATA_REG_REASON	ATA_REG_CNT				/* ATAPI: interrupt reason */
#define	ATA_REG_SECT	3					/* sector */
#define	ATA_REG_LOCYL	4					/* ATA: LSB of cylinder */
#define	ATA_REG_LOCNT	ATA_REG_LOCYL				/* ATAPI: LSB of transfer count */
#define	ATA_REG_HICYL	5					/* ATA: MSB of cylinder */
#define	ATA_REG_HICNT	ATA_REG_HICYL				/* ATAPI: MSB of transfer count */
#define	ATA_REG_DRVHD	6					/* drive select; head */
#define	ATA_REG_CMD	7					/* write: drive command */
#define	ATA_REG_STAT	7					/* read: status and error flags */
#define	ATA_REG_SLCT	0x206					/* write: device control */
#define	ATA_REG_ALTST	0x206					/* read: alternate status/error */
typedef struct /* 'identify' structure, as per ANSI ATA2 rev.2f spec */
{
	u16 Config, PhysCyls, Res2, PhysHeads, UnfBytesPerTrack;
	u16 UnfBytesPerSect, PhysSects, Vendor0, Vendor1, Vendor2;
	u8 SerialNum[20];
	u16 BufType, BufSize, ECCBytes;	u8 FirmwareRev[8], Model[40], MaxMult, Vendor3;	u16 DwordIO;
	u8 Vendor4, Capability;	u16 Res50;
	u8 Vendor5, PIOMode, Vendor6, DMAMode;	u16 LogValid, LogCyls, LogHeads, LogSects;
	u32 TotalSects;	u8 MultSect, MultSectValid;
	u32 LBASects;
	u16 DMAInfoSingle, DMAInfoMult, EIDEPIOModes;
	u16 EIDEDMAMin, EIDEDMATime, EIDEPIO, EIDEPIOIORdy;
	/* This fixed the drive-goes-north-after-ATAPI-identify bug
	u16 Res69, Res70; } ataid; */
	u16 Res[187];
} ataid;

/* generalized drive info structure */
typedef struct{
	u16 Flags;
	u8 DrvSel;
	/* ATA, ATAPI only (LUN for SCSI?) */
	u8 MultSect;
	/* ATA only */
	u16 Sects, Heads, Cyls;
	/* CHS ATA only */
	u16 IOAdr;
} drive;

drive Drive[4];

/*****************************************************************************
name:	ataSelect
*****************************************************************************/
int ataSelect(unsigned int IOAdr, unsigned char Sel)
{
	unsigned char Temp;
	Temp=inp(IOAdr + ATA_REG_DRVHD);
	if(((Temp ^ Sel) & 0x10) == 0) return(0); /* already selected */
	outp(IOAdr + ATA_REG_DRVHD, Sel);
	nsleep(400);
	for(Temp=WAIT_READY; Temp; Temp--)
	{
		if((inp(IOAdr + ATA_REG_STAT) & 0x80) == 0) break;
		msleep(1);
	}
	/* this _must_ be polled, I guess (sigh) */
	return(Temp == 0);
}

/*****************************************************************************
name:	ataProbe2
*****************************************************************************/

void ataProbe2(unsigned char WhichDrive, unsigned char DrvSel)
{
	unsigned char Temp, Temp1, Temp2;
	unsigned int IOAdr;
	ataid DriveInfo;

	IOAdr=Drive[WhichDrive].IOAdr;
	ataSelect(IOAdr, DrvSel);

	Temp1=inp(IOAdr + ATA_REG_CNT);
	Temp2=inp(IOAdr + ATA_REG_SECT);
	if (Temp1 != 0x01 || Temp2 != 0x01)
	{
		printf("nothing there\n");
		NO_DRIVE:
			Drive[WhichDrive].IOAdr=0;
		return;
	}
	Temp1=inp(IOAdr + ATA_REG_LOCYL);
	Temp2=inp(IOAdr + ATA_REG_HICYL);
	Temp=inp(IOAdr + ATA_REG_STAT);
	InterruptOccured=0;
	if (Temp1 == 0x14 && Temp2 == 0xEB)
	{
		printf("ATAPI CD-ROM, ");
		Drive[WhichDrive].Flags |= ATA_FLG_ATAPI;
		// issue ATAPI 'identify drive' command
		Temp1=ATA_CMD_PID;
		outp(IOAdr + ATA_REG_CMD, Temp1);
		Temp=(unsigned char)WAIT_PID;
	}
	else
	if(Temp1 == 0 && Temp2 == 0 && Temp)
	{
		printf("ATA hard drive, ");
		// issue ATA 'identify drive' command
		Temp1=ATA_CMD_ID;
		outp(IOAdr + ATA_REG_CMD, Temp1);
		Temp=(unsigned char)WAIT_ID;
	}
	else
	{
		printf("unknown drive type\n");
		goto NO_DRIVE;
	}
	// ATA or ATAPI: get results of of identify
	nsleep(400);
	if(awaitInterrupt(0xC000, Temp) == 0)
	// XXX - could be old drive that doesn't support 'identify'.Read geometry from partition table? Use (* gag *) CMOS?
	{
		printf("'identify' failed\n");
		goto NO_DRIVE;
	}
	// grab info returned by 'identify'
	(void)inp(IOAdr + ATA_REG_STAT);
	// for ATAPI CD-ROM, you MUST read 512 bytes here, ordrive will go comatose
	insw(IOAdr + ATA_REG_DATA, (u16 *)&DriveInfo, sizeof(DriveInfo) / 2);
	Temp2=1;
	if(Temp1 == ATA_CMD_PID)
	// model name is not byte swapped for NEC, Mitsumi, and Pioneer drives
	{
		if((DriveInfo.Model[0] == 'N' && DriveInfo.Model[1] == 'E') ||
			(DriveInfo.Model[0] == 'F' && DriveInfo.Model[1] == 'X') ||
			(DriveInfo.Model[0] == 'P' && DriveInfo.Model[1] == 'i'))
				Temp2=0;
	}
	for(Temp=0; Temp < 40; Temp += 2)
	{
		printf("%c", DriveInfo.Model[Temp ^ Temp2]);
		printf("%c", DriveInfo.Model[Temp ^ Temp2 ^ 1]);
	}
	printf("\n"
		"CHS=%u:%u:%u, ", DriveInfo.PhysCyls, DriveInfo.PhysHeads,
		DriveInfo.PhysSects);
	Drive[WhichDrive].Sects=DriveInfo.PhysSects;
	Drive[WhichDrive].Heads=DriveInfo.PhysHeads;
	Drive[WhichDrive].Cyls=DriveInfo.PhysCyls;
	if(DriveInfo.Capability & 1)
	{
		printf("DMA, ");
		Drive[WhichDrive].Flags |= ATA_FLG_DMA;
	}
	if(DriveInfo.Capability & 2)
	{
		printf("LBA, ");
		Drive[WhichDrive].Flags |= ATA_FLG_LBA;
	}
	// By Dobbs, I'll figure this out yet. Linux ide.c requires
	// (DriveInfo.MultSectValid & 1) && DriveInfo.MultSect
	// The magic value then comes from DriveInfo.MaxMult
	// QUANTUM FIREBALL ST2.1A			MaxMult=16	MultSect=16	MultSectValid=1
	// Conner Peripherals 850MB - CFS850A	MaxMult=16	MultSect=0	MultSectValid=1
	// (Seagate) st3144AT			MaxMult=0	MultSect=0	MultSectValid=0
	if((DriveInfo.MultSectValid & 1) && DriveInfo.MultSect)
	{
		Temp=DriveInfo.MaxMult;
		printf("MaxMult=%u, ", Temp);
	}
	else
		Temp=1;
	Drive[WhichDrive].MultSect=Temp;
	printf("%uK cache\n", DriveInfo.BufSize >> 1);
#ifdef DEBUG
	printf("\n"
		"Config=0x%hX, PhysCyls=%hu, Res2=%hu, PhysHeads=%hu, "
		"UnfBytesPerTrack=%hu\n"
		"PhysSects=%hu, Vendor0=%hu, Vendor1=%hu, "
		"Vendor2=%hu\n",DriveInfo.Config, DriveInfo.PhysCyls, DriveInfo.Res2, DriveInfo.PhysHeads,DriveInfo.UnfBytesPerTrack, DriveInfo.PhysSects, DriveInfo.Vendor0,DriveInfo.Vendor1, DriveInfo.Vendor2);
	printf("\n"
		"BufType=%hu, BufSize=%hu, ECCBytes=%hu, MaxMult=%hu, Vendor3=%hu, "
		"DwordIO=%hu\n"
		"Vendor4=%hu, Capability=0x%hX\n",DriveInfo.BufType, DriveInfo.BufSize, DriveInfo.ECCBytes, DriveInfo.MaxMult,DriveInfo.Vendor3, DriveInfo.DwordIO, DriveInfo.Vendor4, DriveInfo.Capability);
	printf("\n"
		"Res50=%hu, Vendor5=%hu, PIOMode=%hu, Vendor6=%hu, DMAMode=%hu, "
		"LogValid=%hu, LogCyls=%hu\n"
		"LogHeads=%hu, LogSects=%hu, ",DriveInfo.Res50, DriveInfo.Vendor5, DriveInfo.PIOMode, DriveInfo.Vendor6,DriveInfo.DMAMode, DriveInfo.LogValid, DriveInfo.LogCyls, DriveInfo.LogHeads,DriveInfo.LogSects);
	printf("TotalSects=%lu, MultSect=%hu\n",DriveInfo.TotalSects, DriveInfo.MultSect);printf("MultSectValid=%hu\n"
		"LBASects=%lu\n",DriveInfo.MultSectValid, DriveInfo.LBASects);
	printf("\n"
		"DMAInfoSingle=%hu, DMAInfoMult=%hu, EIDEPIOModes=%hu, EIDEDMAMin=%hu"
		"\n"
		"EIDEDMATime=%hu, EIDEPIO=%hu, EIDEPIOIORdy=%hu\n" "\n",DriveInfo.DMAInfoSingle, DriveInfo.DMAInfoMult, DriveInfo.EIDEPIOModes,DriveInfo.EIDEDMAMin, DriveInfo.EIDEDMATime, DriveInfo.EIDEPIO,DriveInfo.EIDEPIOIORdy);
#endif

}

char soft_reset(unsigned int IOAdr)
{
	unsigned char Temp;

	PRINT_DEBUG(printf("ataProbe: found something on I/F 0x%03X, "
			"doing soft reset...\n", IOAdr);)
	outp(IOAdr + ATA_REG_SLCT, 0x0E);
	nsleep(400);// release soft reset AND enable interrupts from drive
	outp(IOAdr + ATA_REG_SLCT, 0x08);
	nsleep(400);// wait for master
	for(Temp=2000; Temp; Temp--)	// XXX - why 2000?
	{
		if((inp(IOAdr + ATA_REG_STAT) & 0x80) == 0) break;
		msleep(1);
	}
	// XXX - blocking delay
	if(Temp == 0)
	{
		PRINT_DEBUG(printf("ataProbe: no master on I/F 0x%03X\n", IOAdr);)
		return -1;
	}
	return 0;
}

/*****************************************************************************
name:	ataProbe
*****************************************************************************/
void ataProbe(void)
{
	unsigned char Temp, Temp1, Temp2, WhichDrive;
	unsigned int IOAdr;

	printf("ataProbe:\n");
	/* set initial values */
	Drive[0].DrvSel=Drive[2].DrvSel=0xA0;
	Drive[1].DrvSel=Drive[3].DrvSel=0xB0;
	Drive[0].IOAdr=Drive[1].IOAdr=0x1F0;
	Drive[2].IOAdr=Drive[3].IOAdr=0x170;
	for (WhichDrive=0; WhichDrive < 4; WhichDrive += 2)
	{
		IOAdr=Drive[WhichDrive].IOAdr;
		/* poke at the interface to see if anything's there */
		PRINT_DEBUG(printf("ataProbe: poking interface 0x%03X\n", IOAdr);)
		outp(IOAdr + ATA_REG_CNT, 0x55);
		outp(IOAdr + ATA_REG_SECT, 0xAA);
		Temp1=inp(IOAdr + ATA_REG_CNT);
		Temp2=inp(IOAdr + ATA_REG_SECT);
		if(Temp1 != 0x55 || Temp2 != 0xAA)
		/* no master: clobber both master and slave */
		NO_DRIVES:
		{
			Drive[WhichDrive + 1].IOAdr=Drive[WhichDrive].IOAdr=0;
			continue;
		}
		/* soft reset both drives on this I/F (selects master) */
		if (!soft_reset(IOAdr)) { };
//			goto NO_DRIVES;
		/* identify master */
		printf("  hd%1u (0x%03X, master): ", WhichDrive, IOAdr);
		ataProbe2(WhichDrive, 0xA0);
		if (!soft_reset(IOAdr)) { };
//			goto NO_DRIVES;
		/* identify slave */
		printf("  hd%1u (0x%03X,  slave): ", WhichDrive + 1, IOAdr);
		ataProbe2(WhichDrive + 1, 0xB0);
	}
}

/*****************************************************************************
name:	ataCmd2
*****************************************************************************/
void ataCmd2(drivecmd *Cmd, u8 Count, u8 CmdByte)
{
	u8 Sect, DrvHd;	u16 Cyl, IOAdr;	u32 Temp;
	IOAdr=Drive[Cmd->Dev].IOAdr;

	/* compute CHS or LBA register values */
	Temp=Cmd->Blk;
	if(Drive[Cmd->Dev].Flags & ATA_FLG_LBA)
	{
		Sect=Temp;
		/* 28-bit sector adr: low byte */
		Cyl=Temp >> 8;
		/* middle bytes */
		DrvHd=Temp >> 24;

⌨️ 快捷键说明

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