henesyinit from p9f47575dc5 years agoHistory
1134 lines · 20.8 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"io.h"#include	"../port/error.h"#include	"devtab.h" /* Intel 82077A (8272A compatible) floppy controller */ typedef	struct Drive		Drive;typedef	struct Controller	Controller;typedef struct Type		Type; #define DPRINT if(floppydebug)kprintint floppydebug; /* bits in the registers */enum{	/* status registers a & b */	Psra=		0x3f0,	Psrb=		0x3f1, 	/* digital output register */	Pdor=		0x3f2,	Fintena=	0x8,	/* enable floppy interrupt */	Fena=		0x4,	/* 0 == reset controller */ 	/* main status register */	Pmsr=		0x3f4,	Fready=		0x80,	/* ready to be touched */	Ffrom=		0x40,	/* data from controller */	Fbusy=		0x10,	/* operation not over */ 	/* data register */	Pdata=		0x3f5,	Frecal=		0x07,	/* recalibrate cmd */	Fseek=		0x0f,	/* seek cmd */	Fsense=		0x08,	/* sense cmd */	Fread=		0x66,	/* read cmd */	Freadid=	0x4a,	/* read track id */	Fspec=		0x03,	/* set hold times */	Fwrite=		0x45,	/* write cmd */	Fformat=	0x4d,	/* format cmd */	Fmulti=		0x80,	/* or'd with Fread or Fwrite for multi-head */	Fdumpreg=	0x0e,	/* dump internal registers */ 	/* digital input register */	Pdir=		0x3F7,	/* disk changed port (read only) */	Pdsr=		0x3F7,	/* data rate select port (write only) */	Fchange=	0x80,	/* disk has changed */ 	/* status 0 byte */	Drivemask=	3<<0,	Seekend=	1<<5,	Codemask=	(3<<6)|(3<<3), 	/* file types */	Qdir=		0,	Qdata=		(1<<2),	Qctl=		(2<<2),	Qmask=		(3<<2), 	DMAchan=	2,	/* floppy dma channel */}; /* *  types of drive (from PC equipment byte) */enum{	Tnone=		0,	T360kb=		1,	T1200kb=	2,	T720kb=		3,	T1440kb=	4,}; /* *  floppy types (all MFM encoding) */struct Type{	char	*name;	int	dt;		/* compatible drive type */	int	bytes;		/* bytes/sector */	int	sectors;	/* sectors/track */	int	heads;		/* number of heads */	int	steps;		/* steps per cylinder */	int	tracks;		/* tracks/disk */	int	gpl;		/* intersector gap length for read/write */		int	fgpl;		/* intersector gap length for format */	int	rate;		/* rate code */ 	/*	 *  these depend on previous entries and are set filled in	 *  by floppyinit	 */	int	bcode;		/* coded version of bytes for the controller */	long	cap;		/* drive capacity in bytes */	long	tsize;		/* track size in bytes */};Type 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, }, { "5¼DD",	T360kb,  512,  9, 2, 1, 40, 0x2A, 0x50, 2, },};#define NTYPES (sizeof(floppytype)/sizeof(Type)) /* *  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,}; /* *  a floppy drive */struct Drive{	Type	*t;		/* floppy type */	int	dt;		/* drive type */	int	dev; 	ulong	lasttouched;	/* time last touched */	int	cyl;		/* current arm position */	int	confused;	/* needs to be recalibrated */	int	vers; 	int	tcyl;		/* target cylinder */	int	thead;		/* target head */	int	tsec;		/* target sector */	long	len;		/* size of xfer */ 	uchar	*cache;	/* track cache */	int	ccyl;	int	chead; 	Rendez	r;		/* waiting here for motor to spin up */}; /* *  controller for 4 floppys */struct Controller{	QLock;			/* exclusive access to the contoller */ 	Drive	*d;		/* the floppy drives */	Drive	*selected;	int	rate;		/* current rate selected */	uchar	cmd[14];	/* command */	int	ncmd;		  /* # command bytes */	uchar	stat[14];	/* command status */	int	nstat;		  /* # status bytes */	int	confused;	/* controler needs to be reset */	Rendez	r;		/* wait here for command termination */	int	motor;		/* bit mask of spinning disks */	Rendez	kr;		/* for motor watcher */}; Controller	fl; #define MOTORBIT(i)	(1<<((i)+4)) /* *  predeclared */static int	floppycmd(void);static void	floppyeject(Drive*);static void	floppyintr(Ureg*);static void	floppykproc(void*);static void	floppyon(Drive*);static void	floppyoff(Drive*);static void	floppypos(Drive*,long);static int	floppyrecal(Drive*);static int	floppyresult(void);static void	floppyrevive(void);static long	floppyseek(Drive*, long);static int	floppysense(void);static void	floppywait(void);static long	floppyxfer(Drive*, int, void*, long, long);static void	floppyformat(Drive*, char*);static int	cmddone(void*);void Xdelay(int); Dirtab floppydir[]={	"fd0disk",		{Qdata + 0},	0,	0666,	"fd0ctl",		{Qctl + 0},	0,	0666,	"fd1disk",		{Qdata + 1},	0,	0666,	"fd1ctl",		{Qctl + 1},	0,	0666,	"fd2disk",		{Qdata + 2},	0,	0666,	"fd2ctl",		{Qctl + 2},	0,	0666,	"fd3disk",		{Qdata + 3},	0,	0666,	"fd3ctl",		{Qctl + 3},	0,	0666,};#define NFDIR	2	/* directory entries/drive */ 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));} /* *  set floppy drive to its default type */static voidsetdef(Drive *dp){	Type *t; 	for(t = floppytype; t < &floppytype[NTYPES]; t++)		if(dp->dt == t->dt){			dp->t = t;			floppydir[NFDIR*dp->dev].length = dp->t->cap;			break;		}} voidfloppyreset(void){	Drive *dp;	Type *t;	uchar equip;	ulong maxtsize; 	/*	 *  init dependent parameters	 */	maxtsize = 0;	for(t = floppytype; t < &floppytype[NTYPES]; 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;	} 	/*	 *  allocate the drive storage	 */	fl.d = xalloc(conf.nfloppy*sizeof(Drive));	fl.selected = fl.d; 	/*	 *  stop the motors	 */	fl.motor = 0;	delay(10);	outb(Pdor, fl.motor | Fintena | Fena);	delay(10); 	/*	 *  init drives	 */	for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++){		dp->dev = dp - fl.d;		dp->dt = T1440kb;		setdef(dp);		dp->cyl = -1;			/* because we don't know */		dp->cache = (uchar*)xspanalloc(maxtsize, BY2PG, 64*1024);		dp->ccyl = -1;		dp->vers = 1;	} 	/*	 *  read nvram for types of floppies 0 & 1	 */	equip = nvramread(0x10);	if(conf.nfloppy > 0){		fl.d[0].dt = (equip >> 4) & 0xf;		setdef(&fl.d[0]);	}	if(conf.nfloppy > 1){		fl.d[1].dt = equip & 0xf;		setdef(&fl.d[1]);	} 	/*	 *  first operation will recalibrate	 */	fl.confused = 1;	setvec(Floppyvec, floppyintr);} voidfloppyinit(void){} Chan*floppyattach(char *spec){	static int kstarted; 	if(kstarted == 0){		/*		 *  watchdog to turn off the motors		 */		kstarted = 1;		kproc("floppy", floppykproc, 0);	}	return devattach('f', spec);} Chan*floppyclone(Chan *c, Chan *nc){	return devclone(c, nc);} intfloppywalk(Chan *c, char *name){	return devwalk(c, name, floppydir, conf.nfloppy*NFDIR, devgen);} voidfloppystat(Chan *c, char *dp){	devstat(c, dp, floppydir, conf.nfloppy*NFDIR, devgen);} Chan*floppyopen(Chan *c, int omode){	return devopen(c, omode, floppydir, conf.nfloppy*NFDIR, devgen);} voidfloppycreate(Chan *c, char *name, int omode, ulong perm){	USED(c, name, omode, perm);	error(Eperm);} voidfloppyclose(Chan *c){	USED(c);} voidfloppyremove(Chan *c){	USED(c);	error(Eperm);} voidfloppywstat(Chan *c, char *dp){	USED(c, dp);	error(Eperm);} static voidislegal(ulong offset, long n, Drive *dp){	if(offset % dp->t->bytes)		error(Ebadarg);	if(n % dp->t->bytes)		error(Ebadarg);} /* *  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 voidchanged(Chan *c, Drive *dp){	ulong old;	Type *start; 	/*	 *  if floppy has changed or first time through	 */	if((inb(Pdir)&Fchange) || dp->vers == 0){		DPRINT("changed\n");		fldump();		dp->vers++;		setdef(dp);		start = dp->t;		dp->confused = 1;	/* make floppyon recal */		floppyon(dp);		floppyseek(dp, dp->t->heads*dp->t->tsize);		while(waserror()){			while(++dp->t){				if(dp->t == &floppytype[NTYPES])					dp->t = floppytype;				if(dp->dt == dp->t->dt)					break;			}			floppydir[NFDIR*dp->dev].length = dp->t->cap;			floppyon(dp);			DPRINT("changed: trying %s\n", dp->t->name);			fldump();			if(dp->t == start)				nexterror();		}		floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize);		poperror();	} 	old = c->qid.vers;	c->qid.vers = dp->vers;	if(old && old != dp->vers)		error(Eio);} longfloppyread(Chan *c, void *a, long n, ulong offset){	Drive *dp;	long rv, i;	int nn, sec, head, cyl;	long len;	uchar *aa; 	if(c->qid.path == CHDIR)		return devdirread(c, a, n, floppydir, conf.nfloppy*NFDIR, devgen); 	rv = 0;	dp = &fl.d[c->qid.path & ~Qmask];	switch ((int)(c->qid.path & Qmask)) {	case Qdata:		islegal(offset, n, dp);		aa = a; 		qlock(&fl);		if(waserror()){			qunlock(&fl);			nexterror();		}		floppyon(dp);		changed(c, dp);		for(rv = 0; rv < n; rv += len){			/*			 *  truncate xfer at track boundary			 */			dp->len = n - rv;			floppypos(dp, offset+rv);			cyl = dp->tcyl;			head = dp->thead;			len = dp->len;			sec = dp->tsec;			nn = dp->t->tsize; 			/*			 *  read the track			 */			if(dp->ccyl!=cyl || dp->chead!=head){				dp->ccyl = -1;				i = floppyxfer(dp, Fread, dp->cache,					(cyl*dp->t->heads+head)*nn, nn);				if(i != nn){					if(i == 0)						break;					len = 0;					continue;				}				dp->ccyl = cyl;				dp->chead = head;			}			memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len);		}		qunlock(&fl);		poperror(); 

Lines 1–500 of 1134.