henesyinit from p9fce6d0435 years agoHistory
1014 lines · 18.6 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" /* Intel 82077A (8272A compatible) floppy controller */ typedef	struct Drive		Drive;typedef	struct Controller	Controller;typedef struct Type		Type;typedef struct Device		Device; /* registers on the 82077 */struct Device{	uchar		sra;	/* (R/O) status register A */			uchar		srb;	/* (R/O) status register B */	uchar		dor;	/* (R/W) digital output register */	uchar		rsvd3;	/* reserved */	uchar		msr;	/* (R/O) main status register */#define dsr	msr	uchar		fifo;	/* (R/W) data FIFO */	uchar		rsvd6;	/* reserved */	uchar		dir;	/* (R/O) digital input register */#define ccr	dir	uchar		flpctl;	/* (W/O) control (not in 82077) */}; /* bits in the registers */enum{	/* status register A */	Fintpend=	0x80,	/* interrupt pending */ 	/* digital output register */	Fintena=	0x8,	/* enable floppy interrupt */	Fena=		0x4,	/* 0 == reset controller */ 	/* main status register */	Fready=		0x80,	/* ready to be touched */	Ffrom=		0x40,	/* data from controller */	Fbusy=		0x10,	/* operation not over */ 	/* data register */	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 */	Fmulti=		0x80,	/* or'd with Fread or Fwrite for multi-head */	Fdumpreg=	0x0e,	/* dump internal registers */ 	/* disk changed register */	Fchange=	0x80,	/* disk has changed */ 	/* floppy control register (not part of 82077) */	Eject_disc	= 0x80,		/* Eject the floppy */	Sel_82077	= 0x40,		/* Scsi/82077 select */	Drv_id		= 0x04,		/* Drive present flag */	Mid		= 0x03,		/* Media id bits */ 	/* 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),}; /* *  floppy types */struct Type{	char	*name;	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 */ 	/*	 *  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[] ={	{ "MF2HD",	512,	18,	2,	1,	80,	0x1B,	0x54, },	{ "MF1DD",	512,	9,	2,	1,	80,	0x1B,	0x54, },	{ "MF4HD",	1024,	18,	2,	1,	80,	0x1B,	0x54, },	{ "F2HD",	512,	15,	2,	1,	80,	0x2A,	0x50, },	{ "F2DD",	512,	8,	2,	2,	40,	0x2A,	0x50, },	{ "F1DD",	512,	8,	1,	2,	40,	0x2A,	0x50, },};#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;	int	dev; 	ulong	lasttouched;	/* time last touched */	int	cyl;		/* current cylinder */	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	*virtual;	/* track cache */	uchar	*physical;	/* ... */	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 */	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 */ 	uchar	*virtual;	/* kernel buffer for DMA (output) */	uchar	*physical;	/* ... */ 	Rendez	kr;		/* for motor watcher */}; Controller	fl; #define MOTORBIT(i)	(1<<((i)+4)) /* *  predeclared */static int	floppycmd(void);static void	floppyeject(Drive*);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 long	floppythrice(Drive*, int, void*, long, long);static int	cmddone(void*); 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 */ /* *  grab DMA from SCSI */#define GETDMA\{\	qlock(&dmalock);\	dmaowner = Ofloppy;\	((Device*)(FDCTLRL))->flpctl = Sel_82077;\	if(waserror()){\		((Device*)(FDCTLRL))->flpctl = 0;\		qunlock(&dmalock);\		nexterror();\	}\} /* *  let SCSI have DMA */#define PUTDMA\{\	((Device*)(FDCTLRL))->flpctl = 0;\	dmaowner = Oscsi;\	qunlock(&dmalock);\	poperror();\} voidnextfloppyreset(void){	Device *devp = (Device*)(FDCTLRL);	Drive *dp;	Type *t;	ulong p;	long l; 	/*	 *  init dependent parameters	 */	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;	} 	/*	 *  allocate the drive storage	 */	fl.d = xalloc(conf.nfloppy*sizeof(Drive)); 	/*	 *  allocate a page for dma	 */	p = (ulong)xspanalloc(BY2PG, BY2PG, 0);	fl.virtual = (uchar *)kmappa(p);	fl.physical = (uchar*)p; 	/*	 *  reset the chip, leave it off	 */	fl.motor = 0;	devp->flpctl = Sel_82077;	devp->dor = 0;	devp->flpctl = 0; 	/*	 *  init drives	 */	for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++){		dp->dev = dp - fl.d;		dp->t = &floppytype[0];		/* default type */		floppydir[NFDIR*dp->dev].length = dp->t->cap;		dp->cyl = -1;		/* because we don't know */		p = (ulong)xspanalloc(dp->t->tsize, BY2PG, 0);		dp->virtual = (uchar *)kmappa(p);		for(l = BY2PG; l < dp->t->tsize; l += BY2PG)			kmappa(p+l);		dp->physical = (uchar*)p;		dp->ccyl = -1;		dp->vers = 1;	} 	/*	 *  first operation will recalibrate	 */	fl.confused = 1;} voidnextfloppyinit(void){} Chan*nextfloppyattach(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*nextfloppyclone(Chan *c, Chan *nc){	return devclone(c, nc);} intnextfloppywalk(Chan *c, char *name){	return devwalk(c, name, floppydir, conf.nfloppy*NFDIR, devgen);} voidnextfloppystat(Chan *c, char *dp){	devstat(c, dp, floppydir, conf.nfloppy*NFDIR, devgen);} Chan*nextfloppyopen(Chan *c, int omode){	return devopen(c, omode, floppydir, conf.nfloppy*NFDIR, devgen);} voidnextfloppycreate(Chan *c, char *name, int omode, ulong perm){	USED(c, name, omode, perm);	error(Eperm);} voidnextfloppyclose(Chan *c){	USED(c);} voidnextfloppyremove(Chan *c){	USED(c);	error(Eperm);} voidnextfloppywstat(Chan *c, char *dp){	USED(c, dp);	error(Eperm);} static voidislegal(Chan *c, long n, Drive *dp){	if(c->offset % dp->t->bytes)		error(Ebadarg);	if(n % dp->t->bytes)		error(Ebadarg);	if(c->qid.vers!=0 && c->qid.vers!=dp->vers){		c->qid.vers = dp->vers;		error(Eio);	} else		c->qid.vers = dp->vers;} static voidchanged(Chan *c, Drive *dp){	ulong old; 	old = c->qid.vers;	c->qid.vers = dp->vers;	if(old && old!=dp->vers)		error(Eio);} longnextfloppyread(Chan *c, void *a, long n){	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(c, n, dp);		aa = a;		nn = dp->t->tsize; 		qlock(&fl);		if(waserror()){			qunlock(&fl);			fl.confused = 1;			CLRCTL(Cpu_dma);			nexterror();		}		GETDMA;		floppyon(dp);		changed(c, dp);		for(rv = 0; rv < n; rv += len){			/*			 *  truncate xfer at track boundary			 */			dp->len = n - rv;			floppypos(dp, c->offset+rv);			cyl = dp->tcyl;			head = dp->thead;			len = dp->len;			sec = dp->tsec; 			/*			 *  read the track			 */			if(dp->ccyl!=cyl || dp->chead!=head){				dp->ccyl = -1;				i = floppythrice(dp, Fread,0,(cyl*dp->t->heads+head)*nn,nn);				if(i != nn){					if(i == 0)						break;					error(Eio);				}				dp->ccyl = cyl;				dp->chead = head;			}			memmove(aa+rv, dp->virtual + (sec-1)*dp->t->bytes, len);		}		PUTDMA;		qunlock(&fl);		poperror();		break;	case Qctl:		break;	default:		panic("floppyread: bad qid");	} 	return rv;} #define SNCMP(a, b) strncmp(a, b, sizeof(b)-1)longnextfloppywrite(Chan *c, void *a, long n){	Drive *dp;	long rv, i;	char *aa = a; 	rv = 0;	dp = &fl.d[c->qid.path & ~Qmask]; 	switch ((int)(c->qid.path & Qmask)) {	case Qdata:		islegal(c, n, dp);		qlock(&fl);		if(waserror()){			qunlock(&fl);			fl.confused = 1;			CLRCTL(Cpu_dma);			nexterror();		}		GETDMA;		floppyon(dp);		changed(c, dp);		for(rv = 0; rv < n; rv += i){			floppypos(dp, c->offset+rv);			if(dp->tcyl == dp->ccyl)				dp->ccyl = -1;			i = floppythrice(dp, Fwrite, aa+rv, c->offset+rv,				n-rv);			if(i <= 0)				break;

Lines 1–500 of 1014.