Charles.Forsyth20060303644188019 years agoHistory
853 lines · 15.1 KB · C
RawDownload
#include <u.h> #include	"lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"io.h"#include	"ureg.h" #include	"fs.h"#include	"devfloppy.h"  /* Intel 82077A (8272A compatible) floppy controller */ /* This module expects the following functions to be defined * elsewhere:  *  * inb() * outb() * floppyexec() * floppyeject()  * floppysetup0() * floppysetup1() * dmainit() * dmasetup() * dmaend() *  * On DMA systems, floppyexec() should be an empty function;  * on non-DMA systems, dmaend() should be an empty function;  * dmasetup() may enforce maximum transfer sizes.  */ enum {	/* file types */	Qdir=		0, 	Qdata=		(1<<2),	Qctl=		(2<<2),	Qmask=		(3<<2), 	DMAchan=	2,	/* floppy dma channel */}; #define DPRINT if(0)print FType floppytype[] ={ { "3½HD",	T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54,	0, }, { "3½DD",	T1440kb, 512,  9, 2, 1, 80, 0x1B, 0x54, 2, }, { "3½DD",	T720kb,  512,  9, 2, 1, 80, 0x1B, 0x54, 2, }, { "5¼HD",	T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, }, { "5¼DD",	T1200kb, 512,  9, 2, 2, 40, 0x2A, 0x50, 1, }, { "ATT3B1",	T1200kb, 512,  8, 2, 2, 48, 0x2A, 0x50, 1, }, { "5¼DD",	T360kb,  512,  9, 2, 1, 40, 0x2A, 0x50, 2, },}; /* *  bytes per sector encoding for the controller. *  - index for b2c is is (bytes per sector/128). *  - index for c2b is code from b2c */static int b2c[] ={[1]	0,[2]	1,[4]	2,[8]	3,};static int c2b[] ={	128,	256,	512,	1024,}; FController	fl; #define MOTORBIT(i)	(1<<((i)+4)) /* *  predeclared */static int	cmddone(void*);static void	floppyformat(FDrive*, char*);static void	floppykproc(void*);static void	floppypos(FDrive*,long);static int	floppyrecal(FDrive*);static int	floppyresult(void);static void	floppyrevive(void);static vlong	pcfloppyseek(FDrive*, vlong);static int	floppysense(void);static void	floppywait(int);static long	floppyxfer(FDrive*, int, void*, long, long); static voidfldump(void){	DPRINT("sra %ux srb %ux dor %ux msr %ux dir %ux\n", inb(Psra), inb(Psrb),		inb(Pdor), inb(Pmsr), inb(Pdir));} static voidfloppyalarm(Alarm* a){	FDrive *dp; 	for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){		if((fl.motor&MOTORBIT(dp->dev)) && TK2SEC(m->ticks - dp->lasttouched) > 5)			floppyoff(dp);	} 	alarm(5*1000, floppyalarm, 0);	cancel(a);} /* *  set floppy drive to its default type */static voidfloppysetdef(FDrive *dp){	FType *t; 	for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++)		if(dp->dt == t->dt){			dp->t = t;			break;		}} static void_floppydetach(void){	/*	 *  stop the motors	 */	fl.motor = 0;	delay(10);	outb(Pdor, fl.motor | Fintena | Fena);	delay(10);} intfloppyinit(void){	FDrive *dp;	FType *t;	ulong maxtsize;	int mask; 	dmainit(DMAchan); 	floppysetup0(&fl); 	/*	 *  init dependent parameters	 */	maxtsize = 0;	for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){		t->cap = t->bytes * t->heads * t->sectors * t->tracks;		t->bcode = b2c[t->bytes/128];		t->tsize = t->bytes * t->sectors;		if(maxtsize < t->tsize)			maxtsize = t->tsize;	} 	fl.selected = fl.d; 	floppydetach = _floppydetach;	floppydetach(); 	/*	 *  init drives	 */	mask = 0;	for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){		dp->dev = dp - fl.d;		if(dp->dt == Tnone)			continue;		mask |= 1<<dp->dev;		floppysetdef(dp);		dp->cyl = -1;			/* because we don't know */		dp->cache = (uchar*)xspanalloc(maxtsize, BY2PG, 64*1024);		dp->ccyl = -1;		dp->vers = 0;		dp->maxtries = 5;	} 	/*	 *  first operation will recalibrate	 */	fl.confused = 1; 	floppysetup1(&fl); 	/* to turn the motor off when inactive */	alarm(5*1000, floppyalarm, 0); 	return mask;} voidfloppyinitdev(int i, char *name){	if(i >= fl.ndrive)		panic("floppyinitdev");	sprint(name, "fd%d", i);} voidfloppyprintdevs(int i){	if(i >= fl.ndrive)		panic("floppyprintdevs");	print(" fd%d", i);} intfloppyboot(int dev, char *file, Boot *b){	Fs *fs; 	if(strncmp(file, "dos!", 4) == 0)		file += 4;	else if(strchr(file, '!') || strcmp(file, "")==0) {		print("syntax is fd0!file\n");		return -1;	} 	fs = floppygetfspart(dev, "dos", 1);	if(fs == nil)		return -1; 	return fsboot(fs, file, b);} voidfloppyprintbootdevs(int dev){	print(" fd%d", dev);} /* *  check if the floppy has been replaced under foot.  cause *  an error if it has. * *  a seek and a read clears the condition.  this was determined *  experimentally, there has to be a better way. * *  if the read fails, cycle through the possible floppy *  density till one works or we've cycled through all *  possibilities for this drive. */static intchanged(FDrive *dp){	FType *start; 	/*	 *  if floppy has changed or first time through	 */	if((inb(Pdir)&Fchange) || dp->vers == 0){		DPRINT("changed\n");		fldump();		dp->vers++;		floppysetdef(dp);		dp->maxtries = 3;		start = dp->t; 		/* flopppyon fails if there's no drive */		dp->confused = 1;	/* make floppyon recal */		if(floppyon(dp) < 0)			return -1; 		pcfloppyseek(dp, dp->t->heads*dp->t->tsize); 		while(floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize) <= 0){ 			/*			 *  if the xfer attempt doesn't clear the changed bit,			 *  there's no floppy in the drive			 */			if(inb(Pdir)&Fchange)				return -1; 			while(++dp->t){				if(dp->t == &floppytype[nelem(floppytype)])					dp->t = floppytype;				if(dp->dt == dp->t->dt)					break;			} 			/* flopppyon fails if there's no drive */			if(floppyon(dp) < 0)				return -1; 			DPRINT("changed: trying %s\n", dp->t->name);			fldump();			if(dp->t == start)				return -1;		}	} 	return 0;} static intreadtrack(FDrive *dp, int cyl, int head){	int i, nn, sofar;	ulong pos; 	nn = dp->t->tsize;	if(dp->ccyl==cyl && dp->chead==head)		return nn;	pos = (cyl*dp->t->heads+head) * nn;	for(sofar = 0; sofar < nn; sofar += i){		dp->ccyl = -1;		i = floppyxfer(dp, Fread, dp->cache + sofar, pos + sofar, nn - sofar);		if(i <= 0)			return -1;	}	dp->ccyl = cyl;	dp->chead = head;	return nn;} longfloppyread(Fs *fs, void *a, long n){	FDrive *dp;	long rv, offset;	int sec, head, cyl;	long len;	uchar *aa; 	aa = a;	dp = &fl.d[fs->dev]; 	offset = dp->offset;	floppyon(dp);	if(changed(dp))		return -1; 	for(rv = 0; rv < n; rv += len){		/*		 *  all xfers come out of the track cache		 */		dp->len = n - rv;		floppypos(dp, offset+rv);		cyl = dp->tcyl;		head = dp->thead;		len = dp->len;		sec = dp->tsec;		if(readtrack(dp, cyl, head) < 0)			break;		memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len);	}	dp->offset = offset+rv; 	return rv;} void*floppygetfspart(int i, char *name, int chatty){	static Fs fs; 	if(strcmp(name, "dos") != 0){		if(chatty)			print("unknown partition fd%d!%s (use fd%d!dos)\n", i, name, i);		return nil;	} 	fs.dev = i;	fs.diskread = floppyread;	fs.diskseek = floppyseek; 	/* sometimes we get spurious errors and doing it again works */	if(dosinit(&fs) < 0 && dosinit(&fs) < 0){		if(chatty)			print("fd%d!%s does not contain a FAT file system\n", i, name);		return nil;	}	return &fs;} static intreturn0(void*){	return 0;} static voidtimedsleep(int (*f)(void*), void* arg, int ms){	int s;	ulong end; 	end = m->ticks + 1 + MS2TK(ms);	while(m->ticks < end && !(*f)(arg)){		s = spllo();		delay(10);		splx(s);	}} /* *  start a floppy drive's motor. */static intfloppyon(FDrive *dp){	int alreadyon;	int tries; 	if(fl.confused)		floppyrevive(); 	/* start motor and select drive */	dp->lasttouched = m->ticks;	alreadyon = fl.motor & MOTORBIT(dp->dev);	if(!alreadyon){		fl.motor |= MOTORBIT(dp->dev);		outb(Pdor, fl.motor | Fintena | Fena | dp->dev);		/* wait for drive to spin up */		timedsleep(return0, 0, 750); 		/* clear any pending interrupts */		floppysense();	} 	/* set transfer rate */	if(fl.rate != dp->t->rate){		fl.rate = dp->t->rate;		outb(Pdsr, fl.rate);	} 	/* get drive to a known cylinder */	if(dp->confused)		for(tries = 0; tries < 4; tries++)			if(floppyrecal(dp) >= 0)				break;	dp->lasttouched = m->ticks;	fl.selected = dp;	if(dp->confused)		return -1;	return 0;} /* *  stop the floppy if it hasn't been used in 5 seconds */static voidfloppyoff(FDrive *dp){	fl.motor &= ~MOTORBIT(dp->dev);	outb(Pdor, fl.motor | Fintena | Fena | dp->dev);} /* *  send a command to the floppy */static intfloppycmd(void){	int i;	int tries; 	fl.nstat = 0;	for(i = 0; i < fl.ncmd; i++){		for(tries = 0; ; tries++){			if((inb(Pmsr)&(Ffrom|Fready)) == Fready)				break;			if(tries > 1000){				DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i);				fldump(); 				/* empty fifo, might have been a bad command */				floppyresult();				return -1;			}			microdelay(1);		}		outb(Pfdata, fl.cmd[i]);	}	return 0;} /* *  get a command result from the floppy * *  when the controller goes ready waiting for a command *  (instead of sending results), we're done *  */static intfloppyresult(void){

Lines 1–500 of 853.