765 lines · 13.6 KB · C
RawDownload
/* * Papa's got a brand new bag on the side. */#include "all.h"#include "io.h"#include "mem.h" #define dprint(...) if(0)print(__VA_ARGS__) typedef	struct Floppy	Floppy;typedef	struct Ctlr	Ctlr;typedef	struct Type	Type; enum{	Pdor=		0x3f2,	/* motor port */	 Fintena=	 0x8,	/* enable floppy interrupt */	 Fena=		 0x4,	/* 0 == reset controller */ 	Pmsr=		0x3f4,	/* controller main status port */	 Fready=	 0x80,	/* ready to be touched */	 Ffrom=		 0x40,	/* data from controller */	 Fbusy=		 0x10,	/* operation not over */ 	Pdata=		0x3f5,	/* controller data port */	 Frecal=	 0x7,	/* recalibrate cmd */	 Fseek=		 0xf,	/* seek cmd */	 Fsense=	 0x8,	/* sense cmd */	 Fread=		 0x66,	/* read cmd */	 Fwrite=	 0x45,	/* write cmd */	 Fmulti=	 0x80,	/* or'd with Fread or Fwrite for multi-head */ 	/* digital input register */	Pdir=		0x3F7,	/* disk changed port (read only) */	Pdsr=		0x3F7,	/* data rate select port (write only) */	Fchange=	0x80,	/* disk has changed */ 	DMAmode0=	0xb,	DMAmode1=	0xc,	DMAaddr=	0x4,	DMAtop=		0x81,	DMAinit=	0xa,	DMAcount=	0x5, 	Maxfloppy=	4,	/* floppies/controller */ 	/* sector size encodings */	S128=		0,	S256=		1,	S512=		2,	S1024=		3, 	/* status 0 byte */	Floppymask=	3<<0,	Seekend=	1<<5,	Codemask=	(3<<6)|(3<<3),	Cmdexec=	1<<6, 	/* status 1 byte */	Overrun=	0x10,}; #define MOTORBIT(i)	(1<<((i)+4)) /* *  types of drive (from PC equipment byte) */enum{	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 (nelem(floppytype)) /* *  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 Floppy{	Type	*t;	int	dt;	int	dev; 	Timet	lasttouched;	/* time last touched */	int	cyl;		/* current cylinder */	int	confused;	/* needs to be recalibrated (or worse) */	long	offset;		/* current offset */ 	int	tcyl;		/* target cylinder */	int	thead;		/* target head */	int	tsec;		/* target sector */	long	len;	int	maxtries;}; /* *  NEC PD765A controller for 4 floppys */struct Ctlr{	QLock;	Rendez; 	Floppy	d[Maxfloppy];	/* the floppy drives */	int	rw;		/* true if a read or write in progress */	int	seek;		/* one bit for each seek in progress */	uchar	stat[8];	/* status of an operation */	int	intr;	Rendez	r;	int	confused;	int	motor;	Floppy	*selected;	int	rate; 	int 	cdev;	uchar	*ccache;		/* cyclinder cache */	int	ccyl;	int	chead;}; Ctlr	fl; static int	floppysend(int);static int	floppyrcv(void);static int	floppyrdstat(int);static void	floppypos(Floppy*, long);static void	floppywait(char*);static int	floppysense(Floppy*);static int	floppyrecal(Floppy*);static void	floppyon(Floppy*);static long	floppyxfer(Floppy*, int, void*, long);static void	floppyrevive(void); /* *  set floppy drive to its default type */static voidsetdef(Floppy *dp){	Type *t; 	for(t = floppytype; t < &floppytype[NTYPES]; t++)		if(dp->dt == t->dt){			dp->t = t;			break;		}} static voidfloppyintr(Ureg *, void*){	fl.intr = 1;	wakeup(&fl.r);} static voidfloppystop(Floppy *dp){	fl.motor &= ~MOTORBIT(dp->dev);	outb(Pdor, fl.motor | Fintena | Fena | dp->dev);} voidfloppyhalt(void*){	Floppy *dp; 	for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++)		if((fl.motor&MOTORBIT(dp->dev)) && canqlock(&fl)){			floppystop(dp);			qunlock(&fl);		}} voidfloppyproc(void){	Floppy *dp; 	for(;;){		for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++){			if((fl.motor&MOTORBIT(dp->dev))			&& TK2SEC(Ticks - dp->lasttouched) > 5			&& canqlock(&fl)){				floppystop(dp);				qunlock(&fl);			}		}		tsleep(&fl, no, 0, 5000);	} } intfloppyinit(void){	Floppy *dp;	uchar equip;	int nfloppy = 0;	Type *t; 	setvec(Floppyvec, floppyintr, &fl); 	delay(10);	outb(Pdor, 0);	delay(1);	outb(Pdor, Fintena | Fena);	delay(10); 	/*	 *  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;	} 	/*	 *  init drive parameters	 */	for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++){		dp->cyl = -1;		dp->dev = dp - fl.d;		dp->maxtries = 1;	} 	/*	 *  read nvram for types of floppies 0 & 1	 */	equip = nvramread(0x10);	if(Maxfloppy > 0){		fl.d[0].dt = (equip >> 4) & 0xf;		setdef(&fl.d[0]);		nfloppy++;	}	if(Maxfloppy > 1){		fl.d[1].dt = equip & 0xf;		setdef(&fl.d[1]);		nfloppy++;	} 	fl.rate = -1;	fl.motor = 0;	fl.confused = 1;	fl.ccyl = -1;	fl.chead = -1;	fl.cdev = -1;	fl.ccache = (uchar*)ialloc(18*2*512, 64*1024);	if(DMAOK(fl.ccache, 18*2*512) == 0)		panic("floppy: no memory < 16Mb\n"); 	userinit(floppyproc, 0, "floppyproc");	atexit(floppyhalt, 0); 	return nfloppy;} static voidfloppyon(Floppy *dp){	int alreadyon;	int tries; 	if(fl.confused)		floppyrevive(); 	dp->lasttouched = Ticks;	alreadyon = fl.motor & MOTORBIT(dp->dev);	fl.motor |= MOTORBIT(dp->dev);	outb(Pdor, fl.motor | Fintena | Fena | dp->dev); 	/* get motor going */	if(!alreadyon)		tsleep(&u->tsleep, no, 0, 750); 	/* 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 = Ticks;	fl.selected = dp;} static voidfloppyrevive(void){	Floppy *dp; 	/*	 *  reset the controller if it's confused	 */	if(fl.confused){		/* reset controller and turn all motors off */		fl.intr = 0;		splhi();		outb(Pdor, 0);		delay(1);		outb(Pdor, Fintena|Fena);		spllo();		for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++)			dp->confused = 1;		fl.motor = 0;		floppywait("revive");		fl.confused = 0;		outb(Pdsr, 0);	}} static intfloppysend(int data){	int tries; 	for(tries = 0; tries < 1000; tries++){		if((inb(Pmsr)&(Ffrom|Fready)) == Fready){			outb(Pdata, data);			return 0;		}		microdelay(8);	}	return -1;} static intfloppyrcv(void){	int tries;	uchar c; 	for(tries = 0; tries < 1000; tries++){		if((inb(Pmsr)&(Ffrom|Fready)) == (Ffrom|Fready))			return inb(Pdata)&0xff;		microdelay(8);	}	dprint("floppyrcv returns -1 status = %ux\n", c);	return -1;} static intfloppyrdstat(int n){	int i;	int c; 	for(i = 0; i < n; i++){		c = floppyrcv();		if(c < 0)			return -1;		fl.stat[i] = c;	}	return 0;} static voidfloppypos(Floppy *dp, long off){	int lsec;	int cyl; 	lsec = off/dp->t->bytes;	dp->tcyl = lsec/(dp->t->sectors*dp->t->heads);	dp->tsec = (lsec % dp->t->sectors) + 1;	dp->thead = (lsec/dp->t->sectors) % dp->t->heads; 	/*	 *  can't read across cylinder boundaries.	 *  if so, decrement the bytes to be read.	 */	lsec = (off+dp->len)/dp->t->bytes;	cyl = lsec/(dp->t->sectors*dp->t->heads);	if(cyl != dp->tcyl){		dp->len -= (lsec % dp->t->sectors)*dp->t->bytes;		dp->len -= ((lsec/dp->t->sectors) % dp->t->heads)*dp->t->bytes				*dp->t->sectors;	} 	dp->lasttouched = Ticks;	fl.intr = 0;} static intflintr(void*){	return fl.intr;} static voidfloppywait(char *cmd){	tsleep(&u->tsleep, no, flintr, Ticks + 1 + MS2TK(750));	if(fl.intr == 0)		return;	dprint("floppy timed out, cmd=%s\n", cmd);	fl.intr = 0;} static intfloppysense(Floppy *dp){	/*	 *  ask for floppy status	 */	if(floppysend(Fsense) < 0){		fl.confused = 1;		return -1;	}	if(floppyrdstat(2) < 0){		fl.confused = 1;		dp->confused = 1;		return -1;	} 	/*	 *  make sure it's the right drive	 */	if((fl.stat[0] & Floppymask) != dp->dev){		dprint("sense failed, %ux %ux\n", fl.stat[0], fl.stat[1]);		dp->confused = 1;		return -1;	}	return 0;} static intfloppyrecal(Floppy *dp){	fl.intr = 0;	if(floppysend(Frecal) < 0	|| floppysend(dp - fl.d) < 0){		dprint("recalibrate rejected\n");		fl.confused = 0;		return -1;	}	floppywait("recal"); 

Lines 1–500 of 765.