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

📄 floppy.c

📁 nucleus 源码包括具体的内核适合研究 nucleus
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
* Floppy access					*
* v0.1: TDS						*
*       - basic routines		*
* v0.2: TDS (30.03.2004)		*
*       - floppy read/write		*
*       - still buggy DMA code	*
*       - still buggy :-/		*
* v0.3: TDS (26.05.2004)		*
*		- #define TBADDR fixes	*
*		  DMA problem			*
* v0.4: TDS (09.08.2004)		*
*		- now supports up to 2	*
*		  drives still with 	*
*		  problems in detection	*
* v0.5: Doug Gale				*
*		- Fixed CMOS access		*
*		- Relocated DMA buffer	*
*/

#include <stdio.h>
#include <support.h>
#include <datatypes.h>
#include <drivers/dma.h>
#include <drivers/block/floppy.h>
#include <drivers/cmos.h>
#include <drivers/timer.h>
#include <multi.h>
#include <drivers/mem/mem.h>
#include <drivers/block/disk.h>

#include <irqa.h>
#include <interrupts.h>
#include <drivers/pic.h>

#define TBADDR 0x90000    /* physical address of track buffer located below 1M */

/* globals */
volatile BOOL done = FALSE;	// volatile, cos it's changed by an interrupt
int mtick = 0;
dword tmout = 0;
struct floppy_t floppies[2];
unsigned char fdc = 0;

#define floppy (&floppies[fdc])

void floppy_sendbyte(int byte);
int  floppy_getbyte(void);
BOOL floppy_wait(BOOL sensei);
BOOL floppy_read_block(int block, byte *blockbuff, unsigned long nosectors);
BOOL floppy_rw(int block, byte *blockbuff, BOOL read, dword nosectors, BOOL firsttry);
BOOL floppy_seek(int track);
void floppy_recalibrate(void);

/* helper functions */
// Called by IRQ handler
void floppy_process(void)
{
   /* signal operation finished */
   done = TRUE;
   return;
}

void floppy_update(void)
{
	if (tmout)
		tmout--;     /* bump timeout */
   
	if (mtick > 0)
		mtick--;
	else
	if (!mtick && floppy->motor)
	{
		outportb(floppy->FDC_DOR, 0x00);  /* turn off floppy motor, maybe 0x0C? */
		floppy->motor = FALSE;
	}	
}

/*floppy_sendbyte() routine from intel manual */
void floppy_sendbyte(int what)
{
	volatile int msr;
	int tmo;
   
	for (tmo = 0;tmo < 128;tmo++)
	{
		msr = inportb(floppy->FDC_MSR);
		if ((msr & 0xc0) == 0x80)
		{
			outportb(floppy->FDC_DATA, what);
			return;
		}
		inportb(0x80);   /* delay */
	}
}

/* getbyte() routine from intel manual */
int floppy_getbyte(void)
{
	volatile int msr;
	int tmo;
   
	for (tmo = 0;tmo < 128;tmo++)
	{
		msr = inportb(floppy->FDC_MSR);
		if ((msr & 0xd0) == 0xd0)
		{
			return inportb(floppy->FDC_DATA);
		}
		inportb(0x80);   /* delay */
	}
	return -1;   /* read timeout */
}

/* this waits for FDC command to complete */
BOOL floppy_wait(BOOL sensei)
{
	tmout = timer_ticks + 100;
     
	/* wait for IRQ6 handler to signal command finished */
	while (!done && (tmout > timer_ticks))
		multi_yield();

	/* read in command result bytes */
	floppy->statsz = 0;
	while ((floppy->statsz < 7) && (inportb(floppy->FDC_MSR) & (1<<4)))
	{
		floppy->status[floppy->statsz++] = floppy_getbyte();
	}

	if (sensei)
	{
		/* send a "sense interrupt status" command */
		floppy_sendbyte(CMD_SENSEI);
		floppy->sr0 = floppy_getbyte();
		floppy->track = floppy_getbyte();
	}
	done = FALSE;
   
	if (!tmout)
	{
		/* timed out! */
		if (inportb(floppy->FDC_DIR) & 0x80)  /* check for diskchange */
			floppy->dchange = TRUE;
		return FALSE;
	}
	else
		return TRUE;
}

/*
 * converts linear block address to head/track/sector
 * 
 * blocks are numbered 0..heads*tracks*sectors-1
 * blocks 0..sectors-1 are serviced by head #0
 * blocks sectors..sectors*2-1 are serviced by head 1
 * 
 * WARNING: garbage in == garbage out
 */
void block2hts(int block, int *head, int *track, int *sector)
{
	if (floppy->geometry.sectors == 0)
	{
		dprintf("floppy: sectors can't be zero!\n");
		return;
	}	
	*head = ((block % (floppy->geometry.sectors * floppy->geometry.heads)) / (floppy->geometry.sectors));
	*track = (block / (floppy->geometry.sectors * floppy->geometry.heads));
	*sector = ((block % floppy->geometry.sectors) + 1);
}

/**** disk operations ****/

/* this gets the FDC to a known state */
void floppy_reset(void)
{
   /* stop the motor and disable IRQ/DMA */
	outportb(floppy->FDC_DOR, 0x00);
	outportb(floppy->FDC_DOR, 0x0C);
	outportb(floppy->FDC_DOR, 0x00);
	delay(100); // give motor some time to stop
   
	mtick = 0;
	floppy->motor = FALSE;

   /* program data rate (500K/s) */
	outportb(floppy->FDC_DRS, 0);

   /* re-enable interrupts */
	outportb(floppy->FDC_DOR,0x0c);

   /* resetting triggered an interrupt - handle it */
	done = TRUE;
	floppy_wait(TRUE);

   /* specify drive timings (got these off the BIOS) */
	floppy_sendbyte(CMD_SPECIFY);
	floppy_sendbyte(0xdf);  /* SRT = 3ms, HUT = 240ms */
	floppy_sendbyte(0x02);  /* HLT = 16ms, ND = 0 */
   
   /* clear "disk change" status */
	floppy_seek(1);
	floppy_recalibrate();

	floppy->dchange = FALSE;
}

void floppy_status(void)
{
	char * status[] = {
    	"floppy drive 0 in seek mode/busy",
    	"floppy drive 1 in seek mode/busy",
    	"floppy drive 2 in seek mode/busy",
    	"floppy drive 3 in seek mode/busy",
    	"FDC read or write command in progress",
    	"FDC is in non-DMA mode",
    	"I/O direction;  1 = FDC to CPU; 0 = CPU to FDC",
    	"data reg ready for I/O to/from CPU (request for master)"};
	int st = inportb(floppy->FDC_MSR);
	int i;
	
	printf("status: %X\n", st);
	for (i=0; i<8; i++)
    {
		if (st & (1 << i))
		{
			printf("test %d == 0x%x (", i, 1<<i);
			printf("%s)\n", status[i]);
		}
	}
}

/* this returns whether there was a disk change */
BOOL floppy_diskchange(void)
{
	return floppy->dchange;
}

/* this turns the motor on */
void floppy_motoron(void)
{
	if (!floppy->motor)
	{
		mtick = -1;     /* stop motor kill countdown */
		outportb(floppy->FDC_DOR, 0x1C);
		delay(500); /* delay 500ms for motor to spin up */
		floppy->motor = TRUE;
	}
	return;
}

/* this turns the motor off */
void floppy_motoroff(void)
{
   if (floppy->motor) {
      mtick = 13500;   /* start motor kill countdown: 36 ticks ~ 2s */
   }
   return;
}

/* recalibrate the drive */
void floppy_recalibrate(void)
{
   /* turn the motor on */
	floppy_motoron();
   
   /* send actual command bytes */
	floppy_sendbyte(CMD_RECAL);
	floppy_sendbyte(0);

   /* wait until seek finished */
	floppy_wait(TRUE);
   
   /* turn the motor off */
	floppy_motoroff();
}

/* seek to track */
BOOL floppy_seek(int track)
{
	if (floppy->track == track)  /* already there? */
		return TRUE;
   
	floppy_motoron();
   
   /* send actual command bytes */
	floppy_sendbyte(CMD_SEEK);
	floppy_sendbyte(0);
	floppy_sendbyte(track);

   /* wait until seek finished */
	if (!floppy_wait(TRUE))
		return FALSE;     /* timeout! */
	/* now let head settle for 15ms */
	delay(15);
   
	floppy_motoroff();
   
   /* check that seek worked */
	if ((floppy->sr0 != 0x20) || (floppy->track != track))
		return FALSE;
	else
		return TRUE;
}

/* checks drive geometry - call this after any disk change */
BOOL floppy_get_geo(void)
{
	char tmp[512];
	
	/* get drive in a known status before we do anything */
	floppy_reset();

	/* assume disk is 1.68M and try and read block #21 on first track */
	floppy->geometry.cyls = DG168_TRACKS;
	floppy->geometry.heads = DG168_HEADS;
	floppy->geometry.sectors = DG168_SECTORS;
	dprintf("floppy: Checking 1.68MB disk...\n");
	if (floppy_read_block(20, (char *)tmp, 1))
	{
		return TRUE;             
	}
   
	/* OK, not 1.68M - try again for 1.44M reading block #18 on first track */
	floppy->geometry.cyls = DG144_TRACKS;
	floppy->geometry.heads = DG144_HEADS;
	floppy->geometry.sectors = DG144_SECTORS;

	dprintf("floppy: Checking 1.44MB disk...\n");
	if (floppy_read_block(17, (char *)tmp, 1))
	{
		return TRUE;
	}
	/* it's not 1.44M or 1.68M - we don't support it */
	return FALSE;
}

/* read block (blockbuff is 512 byte buffer) */
BOOL floppy_read_block(int block, byte *blockbuff, unsigned long nosectors)
{
	int track=0, sector=0, head=0, track2=0, result=0, loop=0;

// The FDC can read multiple sides at once but not multiple tracks
	
	block2hts(block, &head, &track, &sector);
	block2hts(block+nosectors, &head, &track2, &sector);
	
	if(track!=track2)
	{
		for(loop=0; loop<nosectors; loop++)
			result = floppy_rw(block+loop, blockbuff+(loop*512), TRUE, 1, TRUE);
		return result;
	}
	return floppy_rw(block,blockbuff,TRUE,nosectors, TRUE);
}

/* write block (blockbuff is 512 byte buffer) */
BOOL floppy_write_block(int block,byte *blockbuff, unsigned long nosectors)
{
   return floppy_rw(block,blockbuff,FALSE, nosectors, TRUE);
}

/*
 * since reads and writes differ only by a few lines, this handles both.  This
 * function is called by read_block() and write_block()
 */
BOOL floppy_rw(int block, byte *blockbuff,BOOL read, unsigned long nosectors, BOOL firsttry)
{
	int head,track,sector,tries, copycount = 0;
	unsigned char *p_tbaddr = (char *)TBADDR;
	unsigned char *p_blockbuff = blockbuff;
   
	/* convert logical address into physical address */
	block2hts(block, &head, &track, &sector);

	/* spin up the disk */
	floppy_motoron();

	if (!read && blockbuff)
	{
		/* copy data from data buffer into track buffer */
		for(copycount=0; copycount<(nosectors*512); copycount++)
		{
			*p_tbaddr = *p_blockbuff;
			p_blockbuff++;
			p_tbaddr++;
		}
	}
   
	for (tries = 0; tries < 3; tries++)
	{
		/* check for diskchange */

⌨️ 快捷键说明

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