plan 9 kernel history: overview | file list | diff list

1991/0913/pc/devfloppy.c (diff list | history)

1991/0727/sys/src/9/pc/devfloppy.c:29,431991/0728/sys/src/9/pc/devfloppy.c:29,38 (short | long)
1991/0727    
	 Fwrite=	 0x47,	/* write cmd */ 
	 Fmulti=	 0x80,	/* or'd with Fread or Fwrite for multi-head */ 
 
	DMAmode0=	0xb, 
	DMAmode1=	0xc, 
	DMAaddr=	0x4, 
	DMAtop=		0x81, 
	DMAinit=	0xa, 
	DMAcount=	0x5, 
                 
	Nfloppy=	4,	/* floppies/controller */ 
 
1991/0728    
	DMAchan=	2,	/* floppy dma channel */ 
 
1991/0727    
	/* sector size encodings */ 
	S128=		0, 
	S256=		1, 
1991/0727/sys/src/9/pc/devfloppy.c:48,531991/0728/sys/src/9/pc/devfloppy.c:43,53
1991/0727    
	Drivemask=	3<<0, 
	Seekend=	1<<5, 
	Codemask=	(3<<6)|(3<<3), 
1991/0728    
 
	/* file types */ 
	Qdir=		0, 
	Qdata=		16, 
	Qstruct=	32, 
1991/0727    
}; 
 
/* 
1991/0727/sys/src/9/pc/devfloppy.c:117,1231991/0728/sys/src/9/pc/devfloppy.c:117,123
1991/0727    
	int	confused; 
}; 
 
Controller	floppy[1]; 
1991/0728    
Controller	floppy; 
1991/0727    
 
/* 
 *  start a floppy drive's motor.  set an alarm for 1 second later to 
1991/0727/sys/src/9/pc/devfloppy.c:151,1581991/0728/sys/src/9/pc/devfloppy.c:151,156
1991/0727    
{ 
	int cmd; 
 
	if(!canqlock(dp)) 
		return; 
	cmd = Fintena | Fena | dp->dev; 
	outb(Fmotor, cmd); 
	dp->motoron = 0;	 
1991/0727/sys/src/9/pc/devfloppy.c:162,1751991/0728/sys/src/9/pc/devfloppy.c:160,172
1991/0727    
{ 
	Drive *dp; 
 
	if(waserror()) 
	for(dp = floppy.d; dp < &floppy.d[Nfloppy]; dp++){ 
		if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5) 
1991/0728    
		if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5 
		&& canqlock(dp)){ 
1991/0727    
			floppystop(dp); 
1991/0728    
			qunlock(dp); 
		} 
1991/0727    
	} 
		                 
	alarm(5*1000, floppyalarm, 0); 
	cancel(a); 
} 
 
int 
1991/0727/sys/src/9/pc/devfloppy.c:341,3581991/0728/sys/src/9/pc/devfloppy.c:338,360
1991/0727    
} 
 
void 
floppyinit(void) 
1991/0728    
floppyreset(void) 
1991/0727    
{ 
	Drive *dp; 
 
	for(dp = floppy.d; dp < &floppy.d[Nfloppy]; dp++){ 
		dp->t = &floppytype[0]; 
		dp->cyl = -1; 
1991/0728    
		dp->dev = dp - floppy.d; 
		dp->t = &floppytype[0];		/* default type */ 
1991/0727    
		dp->motoron = 1; 
1991/0728    
		dp->cyl = -1; 
1991/0727    
		floppystop(dp); 
	} 
	setvec(22, floppyintr); 
	alarm(5*1000, floppyalarm, (void *)0); 
1991/0728    
} 
 
void 
floppyinit(void) 
{ 
	kproc(floppykproc, 0); 
1991/0727    
} 
 
void 
1991/0728/sys/src/9/pc/devfloppy.c:163,1691991/0729/sys/src/9/pc/devfloppy.c:163,170 (short | long)
1991/0727    
	for(dp = floppy.d; dp < &floppy.d[Nfloppy]; dp++){ 
1991/0728    
		if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5 
		&& canqlock(dp)){ 
1991/0727    
			floppystop(dp); 
1991/0729    
			if(TK2SEC(m->ticks - dp->lasttouched) > 5) 
				floppystop(dp); 
1991/0728    
			qunlock(dp); 
		} 
1991/0727    
	} 
1991/0729/sys/src/9/pc/devfloppy.c:253,2731991/0730/sys/src/9/pc/devfloppy.c:253,258 (short | long)
1991/0727    
		dp->len -= ((lsec/dp->t->sectors) % dp->t->heads)*secbytes[dp->t->bytes] 
				*dp->t->sectors; 
	} 
                 
	dp->lasttouched = m->ticks;	 
	floppy.intr = 0; 
} 
                 
void 
floppywait(void) 
{ 
	int tries; 
                 
	for(tries = 0; tries < 100 && floppy.intr == 0; tries++) 
		delay(5); 
	if(tries >= 100) 
		print("tired floopy\n"); 
	floppy.intr = 0; 
} 
 
int 
1991/0730/sys/src/9/pc/devfloppy.c:29,351991/0731/sys/src/9/pc/devfloppy.c:29,35 (short | long)
1991/0727    
	 Fwrite=	 0x47,	/* write cmd */ 
	 Fmulti=	 0x80,	/* or'd with Fread or Fwrite for multi-head */ 
 
	Nfloppy=	4,	/* floppies/controller */ 
1991/0731    
	Ndrive=	4,	/* floppies/controller */ 
1991/0727    
 
1991/0728    
	DMAchan=	2,	/* floppy dma channel */ 
 
1991/0730/sys/src/9/pc/devfloppy.c:46,531991/0731/sys/src/9/pc/devfloppy.c:46,53
1991/0728    
 
	/* file types */ 
	Qdir=		0, 
	Qdata=		16, 
	Qstruct=	32, 
1991/0731    
	Qdata=		1, 
	Qstruct=	2, 
1991/0727    
}; 
 
/* 
1991/0730/sys/src/9/pc/devfloppy.c:62,841991/0731/sys/src/9/pc/devfloppy.c:62,102
1991/0727    
	int	steps;		/* steps per cylinder */ 
	int	tracks;		/* tracks/disk */ 
	int	gpl;		/* intersector gap length for read/write */	 
	int	fgpl;		/* intersector gap length for format */	 
1991/0731    
	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 */ 
1991/0727    
	long	cap;		/* drive capacity in bytes */ 
}; 
Type floppytype[] = 
{ 
 { "MF2HD",	S512,	18,	2,	1,	80,	0x1B,	0x54,	512*2*18*80 }, 
 { "MF2DD",	S512,	9,	2,	1,	80,	0x1B,	0x54,	512*2*9*80 }, 
 { "F2HD",	S512,	15,	2,	1,	80,	0x2A,	0x50,	512*15*2*80 }, 
 { "F2DD",	S512,	8,	2,	1,	40,	0x2A,	0x50,	512*8*2*40 }, 
 { "F1DD",	S512,	8,	1,	1,	40,	0x2A,	0x50,	512*8*1*40 }, 
1991/0731    
	{ "MF2HD",	512,	18,	2,	1,	80,	0x1B,	0x54, }, 
	{ "MF2DD",	512,	9,	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, }, 
1991/0727    
}; 
static int secbytes[] = 
1991/0731    
#define NTYPES (sizeof(floppytype)/sizeof(Type)) 
 
/* 
 *  bytes/sector encoding for the controller, index is (bytes per sector/128) 
 */ 
static int b2c[] = 
1991/0727    
{ 
1991/0731    
[1]	0, 
[2]	1, 
[4]	2, 
[8]	3, 
}; 
static int c2b[] = 
{ 
1991/0727    
	128, 
	256, 
	512, 
	1024 
1991/0731    
	1024, 
1991/0727    
}; 
 
/* 
1991/0730/sys/src/9/pc/devfloppy.c:86,921991/0731/sys/src/9/pc/devfloppy.c:104,111
1991/0727    
 */ 
struct Drive 
{ 
	QLock; 
1991/0731    
	QLock;			/* exclusive access to the drive */ 
 
1991/0727    
	Type	*t; 
	int	dev; 
 
1991/0730/sys/src/9/pc/devfloppy.c:99,1081991/0731/sys/src/9/pc/devfloppy.c:118,127
1991/0727    
	int	tcyl;		/* target cylinder */ 
	int	thead;		/* target head */ 
	int	tsec;		/* target sector */ 
	long	len; 
1991/0731    
	long	len;		/* size of xfer */ 
1991/0727    
 
	int	busy;		/* true if drive is seeking */ 
	Rendez	r;		/* waiting for operation termination */ 
1991/0731    
	Rendez	r;		/* waiting here for motor to spin up */ 
1991/0727    
}; 
 
/* 
1991/0730/sys/src/9/pc/devfloppy.c:110,1391991/0731/sys/src/9/pc/devfloppy.c:129,261
1991/0727    
 */ 
struct Controller 
{ 
	QLock; 
	Drive	d[Nfloppy];	/* the floppy drives */ 
1991/0731    
	QLock;			/* exclusive access to the contoller */ 
 
	Drive	d[Ndrive];	/* the floppy drives */ 
1991/0727    
	int	busy;		/* true if a read or write in progress */ 
	uchar	stat[8];	/* status of an operation */ 
	int	confused; 
1991/0731    
	int	intr;		/* true if interrupt occured */ 
	Rendez	r;		/* wait here for command termination */ 
1991/0727    
}; 
 
1991/0728    
Controller	floppy; 
1991/0727    
 
/* 
1991/0731    
 *  predeclared 
 */ 
static void	motoron(Drive*); 
static void	motoroff(Drive*); 
static void	floppykproc(void*); 
static int	floppysend(int); 
static int	floppyrcv(void); 
static int	floppyresult(int); 
static void	floppypos(Drive*); 
static int	floppysense(Drive*); 
static int	interrupted(void*); 
static int	floppyrecal(Drive*); 
static void	floppyrevive(void); 
static long	floppyseek(Drive*); 
static long	floppyxfer(Drive*, int, void*, long); 
static void	floppyintr(Ureg*); 
 
static int 
floppygen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dp) 
{ 
	long l; 
	Drive *dp; 
 
	if(s >= ntab) 
		return -1; 
	if(c->dev >= Ndrive) 
		return -1; 
 
	tab += s; 
	dp = &floppy.d[c->dev]; 
	if((tab->qid.path&~Mask) == Qdata) 
		l = dp->t->cap; 
	else 
		l = 8; 
	devdir(c, tab->qid, tab->name, l, tab->perm, dp); 
	return 1; 
} 
 
void 
floppyreset(void) 
{ 
	Drive *dp; 
 
	for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){ 
		dp->dev = dp - floppy.d; 
		dp->t = &floppytype[0];		/* default type */ 
		dp->motoron = 1; 
		dp->cyl = -1; 
		motoroff(dp); 
	} 
	setvec(Floppyvec, floppyintr); 
} 
 
void 
floppyinit(void) 
{ 
	Type *t; 
 
	/* 
	 *  init dependent parameters 
	 */ 
	for(t = floppytype; t < &floppytype[NTYPES], t++){ 
		t->cap = t->bytes * t->heads * t->sectors * t->tracks; 
		t->bcode = bcode[t->bytes/128]; 
	} 
 
	/* 
	 *  watchdog to turn off the motors 
	 */ 
	kproc(floppykproc, 0); 
} 
long 
floppyread(Chan *c, void *a, long n) 
{ 
	Drive *dp; 
	long rv, i; 
	uchar *aa = a; 
 
	dp = &floppy.d[c->dev]; 
	for(rv = 0; rv < n; rv += i){ 
		i = floppyxfer(dp, Fread, aa+rv, n-rv); 
		if(i <= 0) 
			break; 
	} 
	return rv; 
} 
 
long 
floppywrite(Chan *c, void *a, long n) 
{ 
	Drive *dp; 
	long rv, i; 
	uchar *aa = a; 
 
	dp = &floppy.d[c->dev]; 
	for(rv = 0; rv < n; rv += i){ 
		i = floppyxfer(dp, Fwrite, aa+rv, n-rv); 
		if(i <= 0) 
			break; 
	} 
	return rv; 
} 
 
/* 
1991/0727    
 *  start a floppy drive's motor.  set an alarm for 1 second later to 
 *  mark it as started (we get no interrupt to tell us). 
 * 
 *  assume the caller qlocked the drive. 
 */ 
void 
floppystart(Drive *dp) 
1991/0731    
static void 
motoron(Drive *dp) 
1991/0727    
{ 
	int cmd; 
 
	dp->lasttouched = m->ticks;	 
	if(dp->motoron) 
		return; 
                 
	cmd = (1<<(dp->dev+4)) | Fintena | Fena | dp->dev; 
	outb(Fmotor, cmd); 
	dp->busy = 1; 
1991/0730/sys/src/9/pc/devfloppy.c:146,1531991/0731/sys/src/9/pc/devfloppy.c:268,275
1991/0727    
/* 
 *  stop the floppy if it hasn't been used in 5 seconds 
 */ 
void 
floppystop(Drive *dp) 
1991/0731    
static void 
motoroff(Drive *dp) 
1991/0727    
{ 
	int cmd; 
 
1991/0730/sys/src/9/pc/devfloppy.c:155,1761991/0731/sys/src/9/pc/devfloppy.c:277,301
1991/0727    
	outb(Fmotor, cmd); 
	dp->motoron = 0;	 
} 
void 
floppykproc(Alarm* a) 
1991/0731    
static void 
floppykproc(void *a) 
1991/0727    
{ 
	Drive *dp; 
 
	for(dp = floppy.d; dp < &floppy.d[Nfloppy]; dp++){ 
1991/0731    
	for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){ 
1991/0728    
		if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5 
		&& canqlock(dp)){ 
1991/0729    
			if(TK2SEC(m->ticks - dp->lasttouched) > 5) 
				floppystop(dp); 
1991/0731    
				motoroff(dp); 
1991/0728    
			qunlock(dp); 
		} 
1991/0727    
	} 
} 
 
int 
1991/0731    
/* 
 *  send a byte to the floppy 
 */ 
static int 
1991/0727    
floppysend(int data) 
{ 
	int tries; 
1991/0730/sys/src/9/pc/devfloppy.c:193,1991991/0731/sys/src/9/pc/devfloppy.c:318,327
1991/0727    
	return -1; 
} 
 
int 
1991/0731    
/* 
 *  get a byte from the floppy 
 */ 
static int 
1991/0727    
floppyrcv(void) 
{ 
	int tries; 
1991/0730/sys/src/9/pc/devfloppy.c:215,2221991/0731/sys/src/9/pc/devfloppy.c:343,353
1991/0727    
	return -1; 
} 
 
int 
floppyrdstat(int n) 
1991/0731    
/* 
 *  read a command result message from the floppy 
 */ 
static int 
floppyresult(int n) 
1991/0727    
{ 
	int i; 
	int c; 
1991/0730/sys/src/9/pc/devfloppy.c:230,2431991/0731/sys/src/9/pc/devfloppy.c:361,379
1991/0727    
	return 0; 
} 
 
void 
floppypos(Drive *dp, long off) 
1991/0731    
/* 
 *  calculate physical address of a logical byte offset into the disk 
 * 
 *  truncate dp->length if it crosses a cylinder boundary 
 */ 
static void 
floppypos(Drive *dp) 
1991/0727    
{ 
	int lsec; 
	int end; 
	int cyl; 
 
	lsec = off/secbytes[dp->t->bytes]; 
1991/0731    
	lsec = dp->off/dp->t->bytes; 
1991/0727    
	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; 
1991/0730/sys/src/9/pc/devfloppy.c:246,2611991/0731/sys/src/9/pc/devfloppy.c:382,401
1991/0727    
	 *  can't read across cylinder boundaries. 
	 *  if so, decrement the bytes to be read. 
	 */ 
	lsec = (off+dp->len)/secbytes[dp->t->bytes]; 
1991/0731    
	lsec = (dp->off+dp->len)/dp->t->bytes; 
1991/0727    
	cyl = lsec/(dp->t->sectors*dp->t->heads); 
	if(cyl != dp->tcyl){ 
		dp->len -= (lsec % dp->t->sectors)*secbytes[dp->t->bytes]; 
		dp->len -= ((lsec/dp->t->sectors) % dp->t->heads)*secbytes[dp->t->bytes] 
1991/0731    
		dp->len -= (lsec % dp->t->sectors)*dp->t->bytes; 
		dp->len -= ((lsec/dp->t->sectors) % dp->t->heads)*dp->t->bytes 
1991/0727    
				*dp->t->sectors; 
	} 
} 
 
int 
1991/0731    
/* 
 *  get the interrupt cause from the floppy.  we need to do this 
 *  after seeks and recalibrations since they don't return results. 
 */ 
static int 
1991/0727    
floppysense(Drive *dp) 
{ 
	/* 
1991/0730/sys/src/9/pc/devfloppy.c:265,2711991/0731/sys/src/9/pc/devfloppy.c:405,411
1991/0727    
		floppy.confused = 1; 
		return -1; 
	} 
	if(floppyrdstat(2) < 0){ 
1991/0731    
	if(floppyresult(2) < 0){ 
1991/0727    
		floppy.confused = 1; 
		dp->confused = 1; 
		return -1; 
1991/0730/sys/src/9/pc/devfloppy.c:282,2881991/0731/sys/src/9/pc/devfloppy.c:422,440
1991/0727    
	return 0; 
} 
 
int 
1991/0731    
/* 
 *  return true if interrupt occurred 
 */ 
static int 
interrupted(void *a) 
{ 
	return floppy.intr; 
} 
 
/* 
 *  we've lost the floppy position, go to cylinder 0. 
 */ 
static int 
1991/0727    
floppyrecal(Drive *dp) 
{ 
	floppy.intr = 0; 
1991/0730/sys/src/9/pc/devfloppy.c:291,2971991/0731/sys/src/9/pc/devfloppy.c:443,449
1991/0727    
		floppy.confused = 0; 
		return -1; 
	} 
	floppywait(); 
1991/0731    
	sleep(&floppy.r, interrupted, 0); 
1991/0727    
 
	/* 
	 *  get return values 
1991/0730/sys/src/9/pc/devfloppy.c:323,3551991/0731/sys/src/9/pc/devfloppy.c:475,491
1991/0727    
	return 0; 
} 
 
1991/0731    
/* 
 *  if the controller or a specific drive is in a confused state, 
 *  reset it and get back to a kown state 
 */ 
1991/0727    
void 
1991/0728    
floppyreset(void) 
1991/0731    
floppyrevive(void) 
1991/0727    
{ 
	Drive *dp; 
 
	for(dp = floppy.d; dp < &floppy.d[Nfloppy]; dp++){ 
1991/0728    
		dp->dev = dp - floppy.d; 
		dp->t = &floppytype[0];		/* default type */ 
1991/0727    
		dp->motoron = 1; 
1991/0728    
		dp->cyl = -1; 
1991/0727    
		floppystop(dp); 
	} 
1991/0728    
} 
                 
void 
floppyinit(void) 
{ 
	kproc(floppykproc, 0); 
1991/0727    
} 
                 
void 
floppyreset(void) 
{ 
	Drive *dp; 
                 
	/* 
	 *  reset the floppy if'n it's confused 
1991/0731    
	 *  reset the floppy if it's confused 
1991/0727    
	 */ 
	if(floppy.confused){ 
		/* reset controller and turn all motors off */ 
1991/0730/sys/src/9/pc/devfloppy.c:359,3691991/0731/sys/src/9/pc/devfloppy.c:495,505
1991/0727    
		delay(1); 
		outb(Fmotor, Fintena|Fena); 
		spllo(); 
		for(dp = floppy.d; dp < &floppy.d[Nfloppy]; dp++){ 
1991/0731    
		for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){ 
1991/0727    
			dp->motoron = 0; 
			dp->confused = 1; 
		} 
		floppywait(); 
1991/0731    
		sleep(&floppy.r, interrupted, 0); 
1991/0727    
		floppy.confused = 0; 
	} 
 
1991/0730/sys/src/9/pc/devfloppy.c:370,3761991/0731/sys/src/9/pc/devfloppy.c:506,512
1991/0727    
	/* 
	 *  recalibrate any confused drives 
	 */ 
	for(dp = floppy.d; floppy.confused == 0 && dp < &floppy.d[Nfloppy]; dp++){ 
1991/0731    
	for(dp = floppy.d; floppy.confused == 0 && dp < &floppy.d[Ndrive]; dp++){ 
1991/0727    
		if(dp->confused == 0) 
			floppyrecal(dp); 
 
1991/0730/sys/src/9/pc/devfloppy.c:378,3961991/0731/sys/src/9/pc/devfloppy.c:514,522
1991/0727    
 
} 
 
long 
floppyseek(int dev, long off) 
1991/0731    
static long 
floppyseek(Drive *dp) 
1991/0727    
{ 
	Drive *dp; 
                 
	dp = &floppy.d[dev]; 
                 
	if(floppy.confused || dp->confused) 
		floppyreset(); 
                 
	floppystart(dp); 
                 
	floppypos(dp, off); 
	if(dp->cyl == dp->tcyl){ 
		dp->offset = off; 
		return off; 
1991/0730/sys/src/9/pc/devfloppy.c:400,4061991/0731/sys/src/9/pc/devfloppy.c:526,532
1991/0727    
	 *  tell floppy to seek 
	 */ 
	if(floppysend(Fseek) < 0 
	|| floppysend((dp->thead<<2) | dev) < 0 
1991/0731    
	|| floppysend((dp->thead<<2) | dp->dev) < 0 
1991/0727    
	|| floppysend(dp->tcyl * dp->t->steps) < 0){ 
		print("seek cmd failed\n"); 
		floppy.confused = 1; 
1991/0730/sys/src/9/pc/devfloppy.c:410,4161991/0731/sys/src/9/pc/devfloppy.c:536,542
1991/0727    
	/* 
	 *  wait for interrupt 
	 */ 
	floppywait(); 
1991/0731    
	sleep(&floppy.r, interrupted, 0); 
1991/0727    
 
	/* 
	 *  get floppy status 
1991/0730/sys/src/9/pc/devfloppy.c:441,4821991/0731/sys/src/9/pc/devfloppy.c:567,613
1991/0727    
	return dp->offset; 
} 
 
long 
1991/0731    
static long 
1991/0727    
floppyxfer(Drive *dp, int cmd, void *a, long n) 
{ 
	int dev; 
	ulong addr; 
	long offset; 
 
	addr = (ulong)a; 
	dev = dp - floppy.d; 
 
1991/0731    
	qlock(&floppy); 
	qlock(dp); 
	if(waserror){ 
		qunlock(&floppy); 
		qunlock(dp); 
	} 
 
1991/0727    
	/* 
	 *  dma can't cross 64 k boundaries 
1991/0731    
	 *  get floppy reset and spinning 
1991/0727    
	 */ 
	if((addr & 0xffff0000) != ((addr+n) & 0xffff0000)) 
		n -= (addr+n)&0xffff; 
1991/0731    
	if(floppy.confused || dp->confused) 
		floppyrevive(); 
	if(!dp->motoron) 
		motoron(dp); 
1991/0727    
 
1991/0731    
	/* 
	 *  calculate new position and seek to it (dp->len may be trimmed) 
	 */ 
1991/0727    
	dp->len = n; 
	floppyseek(dev, dp->offset); 
1991/0731    
	floppypos(dp); 
	if(floppyseek(dp) < 0) 
		errors("seeking floppy"); 
1991/0727    
 
/*	print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n", 
1991/0731    
print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n", 
1991/0727    
		dp->tcyl, dp->thead, dp->tsec, addr, n);/**/ 
 
	/* 
	 *  set up the dma 
1991/0731    
	 *  set up the dma (dp->len may be trimmed) 
1991/0727    
	 */ 
	outb(DMAmode1, cmd==Fread ? 0x46 : 0x4a); 
	outb(DMAmode0, cmd==Fread ? 0x46 : 0x4a); 
	outb(DMAaddr, addr); 
	outb(DMAaddr, addr>>8); 
	outb(DMAtop, addr>>16); 
	outb(DMAcount, n-1); 
	outb(DMAcount, (n-1)>>8); 
	outb(DMAinit, 2); 
1991/0731    
	dp->len = dmasetup(2, a, dp->len, cmd==Fread); 
1991/0727    
 
	/* 
	 *  tell floppy to go 
1991/0731    
	 *  start operation 
1991/0727    
	 */ 
	cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0); 
	if(floppysend(cmd) < 0 
1991/0730/sys/src/9/pc/devfloppy.c:484,5071991/0731/sys/src/9/pc/devfloppy.c:615,638
1991/0727    
	|| floppysend(dp->tcyl * dp->t->steps) < 0 
	|| floppysend(dp->thead) < 0 
	|| floppysend(dp->tsec) < 0 
	|| floppysend(dp->t->bytes) < 0 
1991/0731    
	|| floppysend(dp->t->bcode) < 0 
1991/0727    
	|| floppysend(dp->t->sectors) < 0 
	|| floppysend(dp->t->gpl) < 0 
	|| floppysend(0xFF) < 0){ 
		print("xfer cmd failed\n"); 
		floppy.confused = 1; 
		return -1; 
1991/0731    
		errors("floppy command failed"); 
1991/0727    
	} 
 
	floppywait(); 
1991/0731    
	sleep(&floppy.r, interrupted, 0); 
1991/0727    
 
	/* 
	 *  get status 
 	 */ 
	if(floppyrdstat(7) < 0){ 
		print("xfer status failed\n"); 
1991/0731    
	if(floppyresult(7) < 0){ 
print("xfer status failed\n"); 
1991/0727    
		floppy.confused = 1; 
		return -1; 
1991/0731    
		errors("floppy result failed"); 
1991/0727    
	} 
 
	if((floppy.stat[0] & Codemask)!=0 || floppy.stat[1] || floppy.stat[2]){ 
1991/0730/sys/src/9/pc/devfloppy.c:508,5471991/0731/sys/src/9/pc/devfloppy.c:639,667
1991/0727    
print("xfer failed %lux %lux %lux\n", floppy.stat[0], 
			floppy.stat[1], floppy.stat[2]); 
		dp->confused = 1; 
		return -1; 
1991/0731    
		errors("floppy drive lost"); 
1991/0727    
	} 
 
	offset = (floppy.stat[3]/dp->t->steps) * dp->t->heads + floppy.stat[4]; 
	offset = offset*dp->t->sectors + floppy.stat[5] - 1; 
	offset = offset * secbytes[floppy.stat[6]]; 
1991/0731    
	offset = offset * c2b[floppy.stat[6]]; 
1991/0727    
	if(offset != dp->offset+n){ 
		print("new offset %d instead of %d\n", offset, dp->offset+dp->len); 
1991/0731    
print("new offset %d instead of %d\n", offset, dp->offset+dp->len); 
1991/0727    
		dp->confused = 1; 
		return -1;/**/ 
1991/0731    
		errors("floppy drive lost"); 
1991/0727    
	} 
 
1991/0731    
	qunlock(&floppy); 
	qunlock(dp); 
	poperror(); 
 
1991/0727    
	dp->offset += dp->len; 
	return dp->len; 
} 
 
long 
floppyread(int dev, void *a, long n) 
{ 
	Drive *dp; 
	long rv, i; 
	uchar *aa = a; 
                 
	dp = &floppy.d[dev]; 
	for(rv = 0; rv < n; rv += i){ 
		i = floppyxfer(dp, Fread, aa+rv, n-rv); 
		if(i <= 0) 
			break; 
	} 
	return rv; 
} 
                 
void 
1991/0731    
static void 
1991/0727    
floppyintr(Ureg *ur) 
{ 
	floppy.intr = 1; 
1991/0731    
	wakeup(&floppy.r); 
1991/0727    
} 
1991/0731/sys/src/9/pc/devfloppy.c:4,141991/0802/sys/src/9/pc/devfloppy.c:4,14 (short | long)
1991/0727    
#include	"dat.h" 
#include	"fns.h" 
#include	"io.h" 
#include	"ureg.h" 
1991/0802    
#include	"errno.h" 
1991/0727    
 
typedef	struct Drive	Drive; 
1991/0802    
typedef	struct Drive		Drive; 
1991/0727    
typedef	struct Controller	Controller; 
typedef struct Type	Type; 
1991/0802    
typedef struct Type		Type; 
1991/0727    
 
enum 
{ 
1991/0731/sys/src/9/pc/devfloppy.c:46,531991/0802/sys/src/9/pc/devfloppy.c:46,54
1991/0728    
 
	/* file types */ 
	Qdir=		0, 
1991/0731    
	Qdata=		1, 
	Qstruct=	2, 
1991/0802    
	Qdata=		(1<<2), 
	Qstruct=	(2<<2), 
	Qmask=		(3<<2), 
1991/0727    
}; 
 
/* 
1991/0731/sys/src/9/pc/devfloppy.c:82,881991/0802/sys/src/9/pc/devfloppy.c:83,91
1991/0731    
#define NTYPES (sizeof(floppytype)/sizeof(Type)) 
 
/* 
 *  bytes/sector encoding for the controller, index is (bytes per sector/128) 
1991/0802    
 *  bytes per sector encoding for the controller. 
 *  - index for b2c is is (bytes per sector/128). 
 *  - index for c2b is code from b2c 
1991/0731    
 */ 
static int b2c[] = 
1991/0727    
{ 
1991/0731/sys/src/9/pc/devfloppy.c:112,1181991/0802/sys/src/9/pc/devfloppy.c:115,120
1991/0727    
	ulong	lasttouched;	/* time last touched */ 
	int	motoron;	/* motor is on */ 
	int	cyl;		/* current cylinder */ 
	long	offset;		/* current offset */ 
	int	confused;	/* needs to be recalibrated (or worse) */ 
 
	int	tcyl;		/* target cylinder */ 
1991/0731/sys/src/9/pc/devfloppy.c:120,1261991/0802/sys/src/9/pc/devfloppy.c:122,127
1991/0727    
	int	tsec;		/* target sector */ 
1991/0731    
	long	len;		/* size of xfer */ 
1991/0727    
 
	int	busy;		/* true if drive is seeking */ 
1991/0731    
	Rendez	r;		/* waiting here for motor to spin up */ 
1991/0727    
}; 
 
1991/0731/sys/src/9/pc/devfloppy.c:132,1421991/0802/sys/src/9/pc/devfloppy.c:133,144
1991/0731    
	QLock;			/* exclusive access to the contoller */ 
 
	Drive	d[Ndrive];	/* the floppy drives */ 
1991/0727    
	int	busy;		/* true if a read or write in progress */ 
	uchar	stat[8];	/* status of an operation */ 
	int	confused; 
1991/0731    
	int	intr;		/* true if interrupt occured */ 
	Rendez	r;		/* wait here for command termination */ 
1991/0802    
 
	Rendez	kr;		/* for motor watcher */ 
1991/0727    
}; 
 
1991/0728    
Controller	floppy; 
1991/0731/sys/src/9/pc/devfloppy.c:150,1951991/0802/sys/src/9/pc/devfloppy.c:152,201
1991/0731    
static int	floppysend(int); 
static int	floppyrcv(void); 
static int	floppyresult(int); 
static void	floppypos(Drive*); 
1991/0802    
static void	floppypos(Drive*,long); 
1991/0731    
static int	floppysense(Drive*); 
static int	interrupted(void*); 
static int	floppyrecal(Drive*); 
static void	floppyrevive(void); 
static long	floppyseek(Drive*); 
static long	floppyxfer(Drive*, int, void*, long); 
1991/0802    
static long	floppyxfer(Drive*, int, void*, long, long); 
1991/0731    
static void	floppyintr(Ureg*); 
 
static int 
floppygen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dp) 
{ 
	long l; 
	Drive *dp; 
1991/0802    
Dirtab floppydir[]={ 
	"fd0data",		{Qdata + 0},	0,	0600, 
	"fd0struct",		{Qstruct + 0},	8,	0600, 
	"fd1data",		{Qdata + 1},	0,	0600, 
	"fd1struct",		{Qstruct + 1},	8,	0600, 
	"fd2data",		{Qdata + 2},	0,	0600, 
	"fd2struct",		{Qstruct + 2},	8,	0600, 
	"fd3data",		{Qdata + 3},	0,	0600, 
	"fd3struct",		{Qstruct + 3},	8,	0600, 
}; 
#define NFDIR	(sizeof(floppydir)/sizeof(Dirtab)) 
1991/0731    
 
	if(s >= ntab) 
		return -1; 
	if(c->dev >= Ndrive) 
		return -1; 
                 
	tab += s; 
	dp = &floppy.d[c->dev]; 
	if((tab->qid.path&~Mask) == Qdata) 
		l = dp->t->cap; 
	else 
		l = 8; 
	devdir(c, tab->qid, tab->name, l, tab->perm, dp); 
	return 1; 
} 
                 
void 
floppyreset(void) 
{ 
	Drive *dp; 
1991/0802    
	Type *t; 
1991/0731    
 
1991/0802    
	/* 
	 *  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]; 
	} 
 
	/* 
	 *  stop the motors 
	 */ 
1991/0731    
	for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){ 
		dp->dev = dp - floppy.d; 
		dp->t = &floppytype[0];		/* default type */ 
1991/0802    
		floppydir[2*dp->dev].length = dp->t->cap; 
1991/0731    
		dp->motoron = 1; 
		dp->cyl = -1; 
1991/0802    
		dp->cyl = -1;		/* because we don't know */ 
1991/0731    
		motoroff(dp); 
	} 
	setvec(Floppyvec, floppyintr); 
1991/0731/sys/src/9/pc/devfloppy.c:198,2181991/0802/sys/src/9/pc/devfloppy.c:204,277
1991/0731    
void 
floppyinit(void) 
{ 
	Type *t; 
                 
	/* 
	 *  init dependent parameters 
	 */ 
	for(t = floppytype; t < &floppytype[NTYPES], t++){ 
		t->cap = t->bytes * t->heads * t->sectors * t->tracks; 
		t->bcode = bcode[t->bytes/128]; 
	} 
                 
	/* 
	 *  watchdog to turn off the motors 
	 */ 
	kproc(floppykproc, 0); 
1991/0802    
	kproc("floppy", floppykproc, 0); 
1991/0731    
} 
1991/0802    
 
Chan* 
floppyattach(char *spec) 
{ 
	return devattach('f', spec); 
} 
 
Chan* 
floppyclone(Chan *c, Chan *nc) 
{ 
	return devclone(c, nc); 
} 
 
int 
floppywalk(Chan *c, char *name) 
{ 
	return devwalk(c, name, floppydir, NFDIR, devgen); 
} 
 
void 
floppystat(Chan *c, char *dp) 
{ 
	devstat(c, dp, floppydir, NFDIR, devgen); 
} 
 
Chan* 
floppyopen(Chan *c, int omode) 
{ 
	return devopen(c, omode, floppydir, NFDIR, devgen); 
} 
 
void 
floppycreate(Chan *c, char *name, int omode, ulong perm) 
{ 
	error(Eperm); 
} 
 
void 
floppyclose(Chan *c) 
{ 
} 
 
void 
floppyremove(Chan *c) 
{ 
	error(Eperm); 
} 
 
void 
floppywstat(Chan *c, char *dp) 
{ 
	error(Eperm); 
} 
 
static void 
ul2user(uchar *a, ulong x) 
{ 
	a[0] = x >> 24; 
	a[1] = x >> 16; 
	a[2] = x >> 8; 
	a[3] = x; 
} 
 
1991/0731    
long 
floppyread(Chan *c, void *a, long n) 
{ 
1991/0731/sys/src/9/pc/devfloppy.c:220,2301991/0802/sys/src/9/pc/devfloppy.c:279,308
1991/0731    
	long rv, i; 
	uchar *aa = a; 
 
	dp = &floppy.d[c->dev]; 
	for(rv = 0; rv < n; rv += i){ 
		i = floppyxfer(dp, Fread, aa+rv, n-rv); 
		if(i <= 0) 
			break; 
1991/0802    
	if(c->qid.path == CHDIR) 
		return devdirread(c, a, n, floppydir, NFDIR, devgen); 
 
	rv = 0; 
	dp = &floppy.d[c->qid.path & ~Qmask]; 
	switch ((int)(c->qid.path & Qmask)) { 
	case Qdata: 
		for(rv = 0; rv < n; rv += i){ 
			i = floppyxfer(dp, Fread, aa+rv, c->offset+rv, n-rv); 
			if(i <= 0) 
				break; 
		} 
		break; 
	case Qstruct: 
		if (n < 2*sizeof(ulong)) 
			error(Ebadarg); 
		if (c->offset >= 2*sizeof(ulong)) 
			return 0; 
		rv = 2*sizeof(ulong); 
		ul2user((uchar*)a, dp->t->cap); 
		ul2user((uchar*)a+sizeof(ulong), dp->t->bytes); 
		break; 
	default: 
		panic("floppyread: bad qid"); 
1991/0731    
	} 
	return rv; 
} 
1991/0731/sys/src/9/pc/devfloppy.c:236,2521991/0802/sys/src/9/pc/devfloppy.c:314,340
1991/0731    
	long rv, i; 
	uchar *aa = a; 
 
	dp = &floppy.d[c->dev]; 
	for(rv = 0; rv < n; rv += i){ 
		i = floppyxfer(dp, Fwrite, aa+rv, n-rv); 
		if(i <= 0) 
			break; 
1991/0802    
	rv = 0; 
	dp = &floppy.d[c->qid.path & ~Qmask]; 
	switch ((int)(c->qid.path & Qmask)) { 
	case Qdata: 
		for(rv = 0; rv < n; rv += i){ 
			i = floppyxfer(dp, Fwrite, aa+rv, c->offset+rv, n-rv); 
			if(i <= 0) 
				break; 
		} 
		break; 
	case Qstruct: 
		error(Eperm); 
		break; 
	default: 
		panic("floppywrite: bad qid"); 
1991/0731    
	} 
	return rv; 
} 
 
/* 
1991/0727    
 *  start a floppy drive's motor.  set an alarm for 1 second later to 
1991/0802    
 *  start a floppy drive's motor.  set an alarm for .75 second later to 
1991/0727    
 *  mark it as started (we get no interrupt to tell us). 
 * 
 *  assume the caller qlocked the drive. 
1991/0731/sys/src/9/pc/devfloppy.c:258,2671991/0802/sys/src/9/pc/devfloppy.c:346,353
1991/0727    
 
	cmd = (1<<(dp->dev+4)) | Fintena | Fena | dp->dev; 
	outb(Fmotor, cmd); 
	dp->busy = 1; 
	tsleep(&dp->r, noreturn, 0, 1000); 
1991/0802    
	tsleep(&dp->r, return0, 0, 750); 
1991/0727    
	dp->motoron = 1; 
	dp->busy = 0; 
	dp->lasttouched = m->ticks; 
} 
 
1991/0731/sys/src/9/pc/devfloppy.c:282,2941991/0802/sys/src/9/pc/devfloppy.c:368,384
1991/0727    
{ 
	Drive *dp; 
 
1991/0731    
	for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){ 
1991/0728    
		if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5 
		&& canqlock(dp)){ 
1991/0729    
			if(TK2SEC(m->ticks - dp->lasttouched) > 5) 
1991/0731    
				motoroff(dp); 
1991/0728    
			qunlock(dp); 
1991/0802    
	waserror(); 
	for(;;){ 
		for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){ 
			if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5 
			&& canqlock(dp)){ 
				if(TK2SEC(m->ticks - dp->lasttouched) > 5) 
					motoroff(dp); 
				qunlock(dp); 
			} 
1991/0728    
		} 
1991/0802    
		tsleep(&floppy.kr, return0, 0, 5*1000); 
1991/0727    
	} 
} 
 
1991/0731/sys/src/9/pc/devfloppy.c:367,3791991/0802/sys/src/9/pc/devfloppy.c:457,469
1991/0731    
 *  truncate dp->length if it crosses a cylinder boundary 
 */ 
static void 
floppypos(Drive *dp) 
1991/0802    
floppypos(Drive *dp, long off) 
1991/0727    
{ 
	int lsec; 
	int end; 
	int cyl; 
 
1991/0731    
	lsec = dp->off/dp->t->bytes; 
1991/0802    
	lsec = off/dp->t->bytes; 
1991/0727    
	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; 
1991/0731/sys/src/9/pc/devfloppy.c:382,3881991/0802/sys/src/9/pc/devfloppy.c:472,478
1991/0727    
	 *  can't read across cylinder boundaries. 
	 *  if so, decrement the bytes to be read. 
	 */ 
1991/0731    
	lsec = (dp->off+dp->len)/dp->t->bytes; 
1991/0802    
	lsec = (off+dp->len)/dp->t->bytes; 
1991/0727    
	cyl = lsec/(dp->t->sectors*dp->t->heads); 
	if(cyl != dp->tcyl){ 
1991/0731    
		dp->len -= (lsec % dp->t->sectors)*dp->t->bytes; 
1991/0731/sys/src/9/pc/devfloppy.c:414,4201991/0802/sys/src/9/pc/devfloppy.c:504,510
1991/0727    
	/* 
	 *  make sure it's the right drive 
	 */ 
	if((floppy.stat[0] & Drivemask) != dp-floppy.d){ 
1991/0802    
	if((floppy.stat[0] & Drivemask) != dp->dev){ 
1991/0727    
		print("sense failed\n"); 
		dp->confused = 1; 
		return -1; 
1991/0731/sys/src/9/pc/devfloppy.c:517,5301991/0802/sys/src/9/pc/devfloppy.c:607,620
1991/0731    
static long 
floppyseek(Drive *dp) 
1991/0727    
{ 
	if(dp->cyl == dp->tcyl){ 
		dp->offset = off; 
		return off; 
	} 
1991/0802    
	if(dp->cyl == dp->tcyl) 
		return dp->cyl; 
1991/0727    
 
	/* 
	 *  tell floppy to seek 
	 */ 
1991/0802    
	floppy.intr = 0; 
	dp->cyl = -1;	/* once the seek starts it could end anywhere */ 
1991/0727    
	if(floppysend(Fseek) < 0 
1991/0731    
	|| floppysend((dp->thead<<2) | dp->dev) < 0 
1991/0727    
	|| floppysend(dp->tcyl * dp->t->steps) < 0){ 
1991/0731/sys/src/9/pc/devfloppy.c:532,5411991/0802/sys/src/9/pc/devfloppy.c:622,627
1991/0727    
		floppy.confused = 1; 
		return -1; 
	} 
                 
	/* 
	 *  wait for interrupt 
	 */ 
1991/0731    
	sleep(&floppy.r, interrupted, 0); 
1991/0727    
 
	/* 
1991/0731/sys/src/9/pc/devfloppy.c:563,5741991/0802/sys/src/9/pc/devfloppy.c:649,659
1991/0727    
		return -1; 
	} 
 
	dp->offset = off; 
	return dp->offset; 
1991/0802    
	return dp->cyl; 
1991/0727    
} 
 
1991/0731    
static long 
1991/0727    
floppyxfer(Drive *dp, int cmd, void *a, long n) 
1991/0802    
floppyxfer(Drive *dp, int cmd, void *a, long off, long n) 
1991/0727    
{ 
	ulong addr; 
	long offset; 
1991/0731/sys/src/9/pc/devfloppy.c:577,5831991/0802/sys/src/9/pc/devfloppy.c:662,668
1991/0727    
 
1991/0731    
	qlock(&floppy); 
	qlock(dp); 
	if(waserror){ 
1991/0802    
	if(waserror()){ 
1991/0731    
		qunlock(&floppy); 
		qunlock(dp); 
	} 
1991/0731/sys/src/9/pc/devfloppy.c:594,6001991/0802/sys/src/9/pc/devfloppy.c:679,685
1991/0731    
	 *  calculate new position and seek to it (dp->len may be trimmed) 
	 */ 
1991/0727    
	dp->len = n; 
1991/0731    
	floppypos(dp); 
1991/0802    
	floppypos(dp, off); 
1991/0731    
	if(floppyseek(dp) < 0) 
		errors("seeking floppy"); 
1991/0727    
 
1991/0731/sys/src/9/pc/devfloppy.c:609,6171991/0802/sys/src/9/pc/devfloppy.c:694,703
1991/0727    
	/* 
1991/0731    
	 *  start operation 
1991/0727    
	 */ 
1991/0802    
	floppy.intr = 0; 
1991/0727    
	cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0); 
	if(floppysend(cmd) < 0 
	|| floppysend((dp->thead<<2) | dev) < 0 
1991/0802    
	|| floppysend((dp->thead<<2) | dp->dev) < 0 
1991/0727    
	|| floppysend(dp->tcyl * dp->t->steps) < 0 
	|| floppysend(dp->thead) < 0 
	|| floppysend(dp->tsec) < 0 
1991/0731/sys/src/9/pc/devfloppy.c:623,6291991/0802/sys/src/9/pc/devfloppy.c:709,714
1991/0727    
		floppy.confused = 1; 
1991/0731    
		errors("floppy command failed"); 
1991/0727    
	} 
                 
1991/0731    
	sleep(&floppy.r, interrupted, 0); 
1991/0727    
 
	/* 
1991/0731/sys/src/9/pc/devfloppy.c:645,6611991/0802/sys/src/9/pc/devfloppy.c:730,746
1991/0727    
	offset = (floppy.stat[3]/dp->t->steps) * dp->t->heads + floppy.stat[4]; 
	offset = offset*dp->t->sectors + floppy.stat[5] - 1; 
1991/0731    
	offset = offset * c2b[floppy.stat[6]]; 
1991/0727    
	if(offset != dp->offset+n){ 
1991/0731    
print("new offset %d instead of %d\n", offset, dp->offset+dp->len); 
1991/0802    
	if(offset != off+dp->len){ 
print("new offset %d instead of %d\n", offset, off+dp->len); 
1991/0727    
		dp->confused = 1; 
1991/0731    
		errors("floppy drive lost"); 
1991/0727    
	} 
 
1991/0802    
	dp->lasttouched = m->ticks; 
1991/0731    
	qunlock(&floppy); 
	qunlock(dp); 
	poperror(); 
 
1991/0727    
	dp->offset += dp->len; 
	return dp->len; 
} 
 
1991/0802/sys/src/9/pc/devfloppy.c:367,3721991/0803/sys/src/9/pc/devfloppy.c:367,373 (short | long)
1991/0731    
floppykproc(void *a) 
1991/0727    
{ 
	Drive *dp; 
1991/0803    
	int disp = 0; 
1991/0727    
 
1991/0802    
	waserror(); 
	for(;;){ 
1991/0802/sys/src/9/pc/devfloppy.c:378,3841991/0803/sys/src/9/pc/devfloppy.c:379,391
1991/0802    
				qunlock(dp); 
			} 
1991/0728    
		} 
1991/0803    
		disp++; 
		if(owl(disp&1) < 0) 
			print("owl failed\n"); 
		if(mail((disp>>1)&1) < 0) 
			print("mail failed\n"); 
1991/0802    
		tsleep(&floppy.kr, return0, 0, 5*1000); 
1991/0803    
		 
1991/0727    
	} 
} 
 
1991/0803/sys/src/9/pc/devfloppy.c:754,7591991/0806/sys/src/9/pc/devfloppy.c:754,760 (short | long)
1991/0731    
static void 
1991/0727    
floppyintr(Ureg *ur) 
{ 
1991/0806    
print("floppy intr\n"); 
1991/0727    
	floppy.intr = 1; 
1991/0731    
	wakeup(&floppy.r); 
1991/0727    
} 
1991/0806/sys/src/9/pc/devfloppy.c:29,361991/0809/sys/src/9/pc/devfloppy.c:29,34 (short | long)
1991/0727    
	 Fwrite=	 0x47,	/* write cmd */ 
	 Fmulti=	 0x80,	/* or'd with Fread or Fwrite for multi-head */ 
 
1991/0731    
	Ndrive=	4,	/* floppies/controller */ 
1991/0727    
                 
1991/0728    
	DMAchan=	2,	/* floppy dma channel */ 
 
1991/0727    
	/* sector size encodings */ 
1991/0806/sys/src/9/pc/devfloppy.c:123,1281991/0809/sys/src/9/pc/devfloppy.c:121,129
1991/0731    
	long	len;		/* size of xfer */ 
1991/0727    
 
1991/0731    
	Rendez	r;		/* waiting here for motor to spin up */ 
1991/0809    
 
	uchar	*ccache;	/* cylinder cache (always read a whole cyl) */ 
	int	ccyl;		/* number of cached cylinder */ 
1991/0727    
}; 
 
/* 
1991/0806/sys/src/9/pc/devfloppy.c:132,1381991/0809/sys/src/9/pc/devfloppy.c:133,139
1991/0727    
{ 
1991/0731    
	QLock;			/* exclusive access to the contoller */ 
 
	Drive	d[Ndrive];	/* the floppy drives */ 
1991/0809    
	Drive	*d;		/* the floppy drives */ 
1991/0727    
	uchar	stat[8];	/* status of an operation */ 
	int	confused; 
1991/0731    
	int	intr;		/* true if interrupt occured */ 
1991/0806/sys/src/9/pc/devfloppy.c:173,1781991/0809/sys/src/9/pc/devfloppy.c:174,180
1991/0802    
}; 
#define NFDIR	(sizeof(floppydir)/sizeof(Dirtab)) 
1991/0731    
 
1991/0809    
#define k64(x) (((ulong)(x))>>16) 
1991/0731    
void 
floppyreset(void) 
{ 
1991/0806/sys/src/9/pc/devfloppy.c:188,1961991/0809/sys/src/9/pc/devfloppy.c:190,203
1991/0802    
	} 
 
	/* 
1991/0809    
	 *  allocate the drive storage 
	 */ 
	floppy.d = ialloc(conf.nfloppy*sizeof(Drive), 0); 
 
	/* 
1991/0802    
	 *  stop the motors 
	 */ 
1991/0731    
	for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){ 
1991/0809    
	for(dp = floppy.d; dp < &floppy.d[conf.nfloppy]; dp++){ 
1991/0731    
		dp->dev = dp - floppy.d; 
		dp->t = &floppytype[0];		/* default type */ 
1991/0802    
		floppydir[2*dp->dev].length = dp->t->cap; 
1991/0806/sys/src/9/pc/devfloppy.c:198,2031991/0809/sys/src/9/pc/devfloppy.c:205,220
1991/0802    
		dp->cyl = -1;		/* because we don't know */ 
1991/0731    
		motoroff(dp); 
	} 
1991/0809    
 
	/* 
	 *  allocate cylinder caches that don't cross 64k boundaries 
	 */ 
	for(dp = floppy.d; dp < &floppy.d[conf.nfloppy]; dp++){ 
		do { 
			dp->ccache = ialloc(dp->t->cap, 1); 
		} while(k64(dp->ccache) != k64(dp->ccache+dp->t->cap)); 
		dp->ccyl = -1; 
	} 
1991/0731    
	setvec(Floppyvec, floppyintr); 
} 
 
1991/0806/sys/src/9/pc/devfloppy.c:272,2821991/0809/sys/src/9/pc/devfloppy.c:289,304
1991/0802    
	a[3] = x; 
} 
 
1991/0809    
/* 
 *  the floppy is so slow, we always read a cylinder 
 *  at a time and cache the extra bytes. 
 */ 
1991/0731    
long 
floppyread(Chan *c, void *a, long n) 
{ 
	Drive *dp; 
	long rv, i; 
1991/0809    
	long rv, nn, len, cyl; 
	int sec; 
1991/0731    
	uchar *aa = a; 
 
1991/0802    
	if(c->qid.path == CHDIR) 
1991/0806/sys/src/9/pc/devfloppy.c:286,2951991/0809/sys/src/9/pc/devfloppy.c:308,338
1991/0802    
	dp = &floppy.d[c->qid.path & ~Qmask]; 
	switch ((int)(c->qid.path & Qmask)) { 
	case Qdata: 
		for(rv = 0; rv < n; rv += i){ 
			i = floppyxfer(dp, Fread, aa+rv, c->offset+rv, n-rv); 
			if(i <= 0) 
				break; 
1991/0809    
		if(c->offset % dp->t->bytes) 
			errors("bad offset"); 
		if(n % dp->t->bytes) 
			errors("bad len"); 
		nn = dp->t->bytes * dp->t->sectors * dp->t->heads; 
		for(rv = 0; rv < n; rv += len){ 
			/* 
			 *  truncate xfer at cylinder boundary 
			 */ 
			dp->len = n - rv; 
			floppypos(dp, c->offset+rv); 
			cyl = dp->tcyl; 
			len = dp->len; 
			sec = dp->tsec + dp->thead * dp->t->sectors; 
 
			/* 
			 *  read the cylinder 
			 */ 
			if(dp->ccyl != cyl){ 
				dp->ccyl = -1; 
				if(floppyxfer(dp, Fread, dp->ccache, cyl * nn, nn) != nn) 
					errors("floppy read err"); 
				dp->ccyl = cyl; 
			} 
			memmove(aa+rv, dp->ccache + (sec-1)*dp->t->bytes, len); 
1991/0802    
		} 
		break; 
	case Qstruct: 
1991/0806/sys/src/9/pc/devfloppy.c:371,3771991/0809/sys/src/9/pc/devfloppy.c:414,420
1991/0727    
 
1991/0802    
	waserror(); 
	for(;;){ 
		for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){ 
1991/0809    
		for(dp = floppy.d; dp < &floppy.d[conf.nfloppy]; dp++){ 
1991/0802    
			if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5 
			&& canqlock(dp)){ 
				if(TK2SEC(m->ticks - dp->lasttouched) > 5) 
1991/0806/sys/src/9/pc/devfloppy.c:382,3891991/0809/sys/src/9/pc/devfloppy.c:425,430
1991/0803    
		disp++; 
		if(owl(disp&1) < 0) 
			print("owl failed\n"); 
		if(mail((disp>>1)&1) < 0) 
			print("mail failed\n"); 
1991/0802    
		tsleep(&floppy.kr, return0, 0, 5*1000); 
1991/0803    
		 
1991/0727    
	} 
1991/0806/sys/src/9/pc/devfloppy.c:592,5981991/0809/sys/src/9/pc/devfloppy.c:633,639
1991/0727    
		delay(1); 
		outb(Fmotor, Fintena|Fena); 
		spllo(); 
1991/0731    
		for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){ 
1991/0809    
		for(dp = floppy.d; dp < &floppy.d[conf.nfloppy]; dp++){ 
1991/0727    
			dp->motoron = 0; 
			dp->confused = 1; 
		} 
1991/0806/sys/src/9/pc/devfloppy.c:603,6091991/0809/sys/src/9/pc/devfloppy.c:644,650
1991/0727    
	/* 
	 *  recalibrate any confused drives 
	 */ 
1991/0731    
	for(dp = floppy.d; floppy.confused == 0 && dp < &floppy.d[Ndrive]; dp++){ 
1991/0809    
	for(dp = floppy.d; floppy.confused == 0 && dp < &floppy.d[conf.nfloppy]; dp++){ 
1991/0727    
		if(dp->confused == 0) 
			floppyrecal(dp); 
 
1991/0809/sys/src/9/pc/devfloppy.c:180,1851991/0810/sys/src/9/pc/devfloppy.c:180,186 (short | long)
1991/0731    
{ 
	Drive *dp; 
1991/0802    
	Type *t; 
1991/0810    
	int n; 
1991/0731    
 
1991/0802    
	/* 
	 *  init dependent parameters 
1991/0809/sys/src/9/pc/devfloppy.c:211,2181991/0810/sys/src/9/pc/devfloppy.c:212,220
1991/0809    
	 */ 
	for(dp = floppy.d; dp < &floppy.d[conf.nfloppy]; dp++){ 
		do { 
			dp->ccache = ialloc(dp->t->cap, 1); 
		} while(k64(dp->ccache) != k64(dp->ccache+dp->t->cap)); 
1991/0810    
			n = 512 * 18 * 2;	/* MF2HD cylinder size */ 
			dp->ccache = ialloc(n, 1); 
		} while(k64(dp->ccache) != k64(dp->ccache+n)); 
1991/0809    
		dp->ccyl = -1; 
	} 
1991/0731    
	setvec(Floppyvec, floppyintr); 
1991/0810/sys/src/9/pc/devfloppy.c:172,1781991/0811/sys/src/9/pc/devfloppy.c:172,178 (short | long)
1991/0802    
	"fd3data",		{Qdata + 3},	0,	0600, 
	"fd3struct",		{Qstruct + 3},	8,	0600, 
}; 
#define NFDIR	(sizeof(floppydir)/sizeof(Dirtab)) 
1991/0811    
#define NFDIR	2	/* directory entries/drive */ 
1991/0731    
 
1991/0809    
#define k64(x) (((ulong)(x))>>16) 
1991/0731    
void 
1991/0810/sys/src/9/pc/devfloppy.c:201,2071991/0811/sys/src/9/pc/devfloppy.c:201,207
1991/0809    
	for(dp = floppy.d; dp < &floppy.d[conf.nfloppy]; dp++){ 
1991/0731    
		dp->dev = dp - floppy.d; 
		dp->t = &floppytype[0];		/* default type */ 
1991/0802    
		floppydir[2*dp->dev].length = dp->t->cap; 
1991/0811    
		floppydir[NFDIR*dp->dev].length = dp->t->cap; 
1991/0731    
		dp->motoron = 1; 
1991/0802    
		dp->cyl = -1;		/* because we don't know */ 
1991/0731    
		motoroff(dp); 
1991/0810/sys/src/9/pc/devfloppy.c:244,2621991/0811/sys/src/9/pc/devfloppy.c:244,262
1991/0802    
int 
floppywalk(Chan *c, char *name) 
{ 
	return devwalk(c, name, floppydir, NFDIR, devgen); 
1991/0811    
	return devwalk(c, name, floppydir, conf.nfloppy*NFDIR, devgen); 
1991/0802    
} 
 
void 
floppystat(Chan *c, char *dp) 
{ 
	devstat(c, dp, floppydir, NFDIR, devgen); 
1991/0811    
	devstat(c, dp, floppydir, conf.nfloppy*NFDIR, devgen); 
1991/0802    
} 
 
Chan* 
floppyopen(Chan *c, int omode) 
{ 
	return devopen(c, omode, floppydir, NFDIR, devgen); 
1991/0811    
	return devopen(c, omode, floppydir, conf.nfloppy*NFDIR, devgen); 
1991/0802    
} 
 
void 
1991/0810/sys/src/9/pc/devfloppy.c:304,3101991/0811/sys/src/9/pc/devfloppy.c:304,310
1991/0731    
	uchar *aa = a; 
 
1991/0802    
	if(c->qid.path == CHDIR) 
		return devdirread(c, a, n, floppydir, NFDIR, devgen); 
1991/0811    
		return devdirread(c, a, n, floppydir, conf.nfloppy*NFDIR, devgen); 
1991/0802    
 
	rv = 0; 
	dp = &floppy.d[c->qid.path & ~Qmask]; 
1991/0811/sys/src/9/pc/devfloppy.c:31,421991/0823/sys/src/9/pc/devfloppy.c:31,36 (short | long)
1991/0727    
 
1991/0728    
	DMAchan=	2,	/* floppy dma channel */ 
 
1991/0727    
	/* sector size encodings */ 
	S128=		0, 
	S256=		1, 
	S512=		2, 
	S1024=		3, 
                 
	/* status 0 byte */ 
	Drivemask=	3<<0, 
	Seekend=	1<<5, 
1991/0811/sys/src/9/pc/devfloppy.c:45,511991/0823/sys/src/9/pc/devfloppy.c:39,44
1991/0728    
	/* file types */ 
	Qdir=		0, 
1991/0802    
	Qdata=		(1<<2), 
	Qstruct=	(2<<2), 
	Qmask=		(3<<2), 
1991/0727    
}; 
 
1991/0811/sys/src/9/pc/devfloppy.c:163,1761991/0823/sys/src/9/pc/devfloppy.c:156,165
1991/0731    
static void	floppyintr(Ureg*); 
 
1991/0802    
Dirtab floppydir[]={ 
	"fd0data",		{Qdata + 0},	0,	0600, 
	"fd0struct",		{Qstruct + 0},	8,	0600, 
	"fd1data",		{Qdata + 1},	0,	0600, 
	"fd1struct",		{Qstruct + 1},	8,	0600, 
	"fd2data",		{Qdata + 2},	0,	0600, 
	"fd2struct",		{Qstruct + 2},	8,	0600, 
	"fd3data",		{Qdata + 3},	0,	0600, 
	"fd3struct",		{Qstruct + 3},	8,	0600, 
1991/0823    
	"fd0disk",		{Qdata + 0},	0,	0600, 
	"fd1disk",		{Qdata + 1},	0,	0600, 
	"fd2disk",		{Qdata + 2},	0,	0600, 
	"fd3disk",		{Qdata + 3},	0,	0600, 
1991/0802    
}; 
1991/0811    
#define NFDIR	2	/* directory entries/drive */ 
1991/0731    
 
1991/0811/sys/src/9/pc/devfloppy.c:337,3511991/0823/sys/src/9/pc/devfloppy.c:326,331
1991/0809    
			memmove(aa+rv, dp->ccache + (sec-1)*dp->t->bytes, len); 
1991/0802    
		} 
		break; 
	case Qstruct: 
		if (n < 2*sizeof(ulong)) 
			error(Ebadarg); 
		if (c->offset >= 2*sizeof(ulong)) 
			return 0; 
		rv = 2*sizeof(ulong); 
		ul2user((uchar*)a, dp->t->cap); 
		ul2user((uchar*)a+sizeof(ulong), dp->t->bytes); 
		break; 
	default: 
		panic("floppyread: bad qid"); 
1991/0731    
	} 
1991/0811/sys/src/9/pc/devfloppy.c:369,3771991/0823/sys/src/9/pc/devfloppy.c:349,354
1991/0802    
				break; 
		} 
		break; 
	case Qstruct: 
		error(Eperm); 
		break; 
	default: 
		panic("floppywrite: bad qid"); 
1991/0731    
	} 
1991/0811/sys/src/9/pc/devfloppy.c:733,7391991/0823/sys/src/9/pc/devfloppy.c:710,716
1991/0731    
	if(floppyseek(dp) < 0) 
		errors("seeking floppy"); 
1991/0727    
 
1991/0731    
print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n", 
1991/0823    
/*print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n", 
1991/0727    
		dp->tcyl, dp->thead, dp->tsec, addr, n);/**/ 
 
	/* 
1991/0811/sys/src/9/pc/devfloppy.c:797,8031991/0823/sys/src/9/pc/devfloppy.c:774,780
1991/0731    
static void 
1991/0727    
floppyintr(Ureg *ur) 
{ 
1991/0806    
print("floppy intr\n"); 
1991/0823    
/*print("floppy intr\n");/**/ 
1991/0727    
	floppy.intr = 1; 
1991/0731    
	wakeup(&floppy.r); 
1991/0727    
} 
1991/0823/sys/src/9/pc/devfloppy.c:26,341991/0831/sys/src/9/pc/devfloppy.c:26,37 (short | long)
1991/0727    
	 Fseek=		 0xf,	/* seek cmd */ 
	 Fsense=	 0x8,	/* sense cmd */ 
	 Fread=		 0x66,	/* read cmd */ 
	 Fwrite=	 0x47,	/* write cmd */ 
1991/0831    
	 Fwrite=	 0x45,	/* write cmd */ 
1991/0727    
	 Fmulti=	 0x80,	/* or'd with Fread or Fwrite for multi-head */ 
 
1991/0831    
	Fchanged=	0x3F7,	/* disk changed register */ 
	 Fchange=	 0x80,	/* disk has changed */ 
 
1991/0728    
	DMAchan=	2,	/* floppy dma channel */ 
 
1991/0727    
	/* status 0 byte */ 
1991/0823/sys/src/9/pc/devfloppy.c:281,2861991/0831/sys/src/9/pc/devfloppy.c:284,301
1991/0802    
} 
 
1991/0809    
/* 
1991/0831    
 *  look for a floppy change 
 */ 
void 
floppychange(Drive *dp) 
{ 
	if((inb(Fchanged) & Fchange) == 0) 
		return; 
 
	 
} 
 
/* 
1991/0809    
 *  the floppy is so slow, we always read a cylinder 
 *  at a time and cache the extra bytes. 
 */ 
1991/0823/sys/src/9/pc/devfloppy.c:299,3041991/0831/sys/src/9/pc/devfloppy.c:314,320
1991/0802    
	dp = &floppy.d[c->qid.path & ~Qmask]; 
	switch ((int)(c->qid.path & Qmask)) { 
	case Qdata: 
1991/0831    
		floppychanged(dp); 
1991/0809    
		if(c->offset % dp->t->bytes) 
			errors("bad offset"); 
		if(n % dp->t->bytes) 
1991/0823/sys/src/9/pc/devfloppy.c:343,3481991/0831/sys/src/9/pc/devfloppy.c:359,366
1991/0802    
	dp = &floppy.d[c->qid.path & ~Qmask]; 
	switch ((int)(c->qid.path & Qmask)) { 
	case Qdata: 
1991/0831    
		floppychanged(dp); 
		dp->ccyl = -1; 
1991/0802    
		for(rv = 0; rv < n; rv += i){ 
			i = floppyxfer(dp, Fwrite, aa+rv, c->offset+rv, n-rv); 
			if(i <= 0) 
1991/0831/sys/src/9/pc/devfloppy.c:287,2931991/0902/sys/src/9/pc/devfloppy.c:287,293 (short | long)
1991/0831    
 *  look for a floppy change 
 */ 
void 
floppychange(Drive *dp) 
1991/0902    
floppychanged(Drive *dp) 
1991/0831    
{ 
	if((inb(Fchanged) & Fchange) == 0) 
		return; 
1991/0902/sys/src/9/pc/devfloppy.c:700,7101991/0906/sys/src/9/pc/devfloppy.c:700,707 (short | long)
1991/0731    
static long 
1991/0802    
floppyxfer(Drive *dp, int cmd, void *a, long off, long n) 
1991/0727    
{ 
	ulong addr; 
	long offset; 
 
	addr = (ulong)a; 
                 
1991/0731    
	qlock(&floppy); 
	qlock(dp); 
1991/0802    
	if(waserror()){ 
1991/0902/sys/src/9/pc/devfloppy.c:728,7351991/0906/sys/src/9/pc/devfloppy.c:725,733
1991/0731    
	if(floppyseek(dp) < 0) 
		errors("seeking floppy"); 
1991/0727    
 
1991/0906    
	 
1991/0823    
/*print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n", 
1991/0727    
		dp->tcyl, dp->thead, dp->tsec, addr, n);/**/ 
1991/0906    
		dp->tcyl, dp->thead, dp->tsec, a, n);/**/ 
1991/0727    
 
	/* 
1991/0731    
	 *  set up the dma (dp->len may be trimmed) 
1991/0906/sys/src/9/pc/devfloppy.c:420,4271991/0913/sys/src/9/pc/devfloppy.c:420,425 (short | long)
1991/0802    
			} 
1991/0728    
		} 
1991/0803    
		disp++; 
		if(owl(disp&1) < 0) 
			print("owl failed\n"); 
1991/0802    
		tsleep(&floppy.kr, return0, 0, 5*1000); 
1991/0803    
		 
1991/0727    
	} 
1991/0913/sys/src/9/pc/devfloppy.c:409,4151991/0919/sys/src/9/pc/devfloppy.c:409,416 (short | long)
1991/0727    
	Drive *dp; 
1991/0803    
	int disp = 0; 
1991/0727    
 
1991/0802    
	waserror(); 
1991/0919    
	while(waserror()) 
		; 
1991/0802    
	for(;;){ 
1991/0809    
		for(dp = floppy.d; dp < &floppy.d[conf.nfloppy]; dp++){ 
1991/0802    
			if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5 
1991/0919/sys/src/9/pc/devfloppy.c:6,111991/0920/sys/src/9/pc/devfloppy.c:6,13 (short | long)
1991/0727    
#include	"io.h" 
1991/0802    
#include	"errno.h" 
1991/0727    
 
1991/0920    
/* NEC PD765A (8272A compatible) floppy controller */ 
 
1991/0802    
typedef	struct Drive		Drive; 
1991/0727    
typedef	struct Controller	Controller; 
1991/0802    
typedef struct Type		Type; 
1991/0919/sys/src/9/pc/devfloppy.c:42,471991/0920/sys/src/9/pc/devfloppy.c:44,50
1991/0728    
	/* file types */ 
	Qdir=		0, 
1991/0802    
	Qdata=		(1<<2), 
1991/0920    
	Qctl=		(2<<2), 
1991/0802    
	Qmask=		(3<<2), 
1991/0727    
}; 
 
1991/0919/sys/src/9/pc/devfloppy.c:160,1681991/0920/sys/src/9/pc/devfloppy.c:163,175
1991/0731    
 
1991/0802    
Dirtab floppydir[]={ 
1991/0823    
	"fd0disk",		{Qdata + 0},	0,	0600, 
1991/0920    
	"fd0ctl",		{Qctl + 0},	0,	0600, 
1991/0823    
	"fd1disk",		{Qdata + 1},	0,	0600, 
1991/0920    
	"fd1ctl",		{Qctl + 1},	0,	0600, 
1991/0823    
	"fd2disk",		{Qdata + 2},	0,	0600, 
1991/0920    
	"fd2ctl",		{Qctl + 2},	0,	0600, 
1991/0823    
	"fd3disk",		{Qdata + 3},	0,	0600, 
1991/0920    
	"fd3ctl",		{Qctl + 3},	0,	0600, 
1991/0802    
}; 
1991/0811    
#define NFDIR	2	/* directory entries/drive */ 
1991/0731    
 
1991/0919/sys/src/9/pc/devfloppy.c:215,2291991/0920/sys/src/9/pc/devfloppy.c:222,241
1991/0731    
void 
floppyinit(void) 
{ 
	/* 
	 *  watchdog to turn off the motors 
	 */ 
1991/0802    
	kproc("floppy", floppykproc, 0); 
1991/0731    
} 
1991/0802    
 
Chan* 
floppyattach(char *spec) 
{ 
1991/0920    
	static int kstarted; 
 
	if(kstarted == 0){ 
		/* 
		 *  watchdog to turn off the motors 
		 */ 
		kstarted = 1; 
		kproc("floppy", floppykproc, 0); 
	} 
1991/0802    
	return devattach('f', spec); 
} 
 
1991/0919/sys/src/9/pc/devfloppy.c:274,2881991/0920/sys/src/9/pc/devfloppy.c:286,291
1991/0802    
	error(Eperm); 
} 
 
static void 
ul2user(uchar *a, ulong x) 
{ 
	a[0] = x >> 24; 
	a[1] = x >> 16; 
	a[2] = x >> 8; 
	a[3] = x; 
} 
                 
1991/0809    
/* 
1991/0831    
 *  look for a floppy change 
 */ 
1991/0919/sys/src/9/pc/devfloppy.c:292,2981991/0920/sys/src/9/pc/devfloppy.c:295,301
1991/0831    
	if((inb(Fchanged) & Fchange) == 0) 
		return; 
 
	                 
1991/0920    
	print("floppy has changed\n"); 
1991/0831    
} 
 
/* 
1991/0920/sys/src/9/pc/devfloppy.c:110,1161991/0921/sys/src/9/pc/devfloppy.c:110,115 (short | long)
1991/0727    
	int	dev; 
 
	ulong	lasttouched;	/* time last touched */ 
	int	motoron;	/* motor is on */ 
	int	cyl;		/* current cylinder */ 
	int	confused;	/* needs to be recalibrated (or worse) */ 
 
1991/0920/sys/src/9/pc/devfloppy.c:137,1421991/0921/sys/src/9/pc/devfloppy.c:136,142
1991/0727    
	int	confused; 
1991/0731    
	int	intr;		/* true if interrupt occured */ 
	Rendez	r;		/* wait here for command termination */ 
1991/0921    
	int	motor; 
1991/0802    
 
	Rendez	kr;		/* for motor watcher */ 
1991/0727    
}; 
1991/0920/sys/src/9/pc/devfloppy.c:143,1481991/0921/sys/src/9/pc/devfloppy.c:143,150
1991/0727    
 
1991/0728    
Controller	floppy; 
1991/0727    
 
1991/0921    
#define MOTORBIT(i)	(1<<((i)+4)) 
 
1991/0727    
/* 
1991/0731    
 *  predeclared 
 */ 
1991/0920/sys/src/9/pc/devfloppy.c:201,2071991/0921/sys/src/9/pc/devfloppy.c:203,209
1991/0731    
		dp->dev = dp - floppy.d; 
		dp->t = &floppytype[0];		/* default type */ 
1991/0811    
		floppydir[NFDIR*dp->dev].length = dp->t->cap; 
1991/0731    
		dp->motoron = 1; 
1991/0921    
		floppy.motor |= MOTORBIT(dp->dev); 
1991/0802    
		dp->cyl = -1;		/* because we don't know */ 
1991/0731    
		motoroff(dp); 
	} 
1991/0920/sys/src/9/pc/devfloppy.c:376,4121991/0921/sys/src/9/pc/devfloppy.c:378,384
1991/0731    
	return rv; 
} 
 
/* 
1991/0802    
 *  start a floppy drive's motor.  set an alarm for .75 second later to 
1991/0727    
 *  mark it as started (we get no interrupt to tell us). 
 * 
 *  assume the caller qlocked the drive. 
 */ 
1991/0731    
static void 
motoron(Drive *dp) 
1991/0727    
{ 
	int cmd; 
                 
	cmd = (1<<(dp->dev+4)) | Fintena | Fena | dp->dev; 
	outb(Fmotor, cmd); 
1991/0802    
	tsleep(&dp->r, return0, 0, 750); 
1991/0727    
	dp->motoron = 1; 
	dp->lasttouched = m->ticks; 
} 
                 
/* 
 *  stop the floppy if it hasn't been used in 5 seconds 
 */ 
1991/0731    
static void 
motoroff(Drive *dp) 
1991/0727    
{ 
	int cmd; 
                 
	cmd = Fintena | Fena | dp->dev; 
	outb(Fmotor, cmd); 
	dp->motoron = 0;	 
} 
1991/0731    
static void 
floppykproc(void *a) 
1991/0727    
{ 
	Drive *dp; 
1991/0920/sys/src/9/pc/devfloppy.c:416,4221991/0921/sys/src/9/pc/devfloppy.c:388,395
1991/0919    
		; 
1991/0802    
	for(;;){ 
1991/0809    
		for(dp = floppy.d; dp < &floppy.d[conf.nfloppy]; dp++){ 
1991/0802    
			if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5 
1991/0921    
			if((floppy.motor&MOTORBIT(dp->dev)) 
			&& TK2SEC(m->ticks - dp->lasttouched) > 5 
1991/0802    
			&& canqlock(dp)){ 
				if(TK2SEC(m->ticks - dp->lasttouched) > 5) 
					motoroff(dp); 
1991/0920/sys/src/9/pc/devfloppy.c:429,4351991/0921/sys/src/9/pc/devfloppy.c:402,448
1991/0727    
	} 
} 
 
1991/0921    
static void 
driveselect(Drive *dp) 
{ 
	int cmd; 
 
	cmd = floppy.motor | Fintena | Fena | dp->dev; 
	outb(Fmotor, cmd); 
} 
 
1991/0731    
/* 
1991/0921    
 *  start a floppy drive's motor.  set an alarm for .75 second later to 
 *  mark it as started (we get no interrupt to tell us). 
 * 
 *  assume the caller qlocked the drive. 
 * 
 *  this also selects the drive for subsequent operations 
 */ 
static void 
motoron(Drive *dp) 
{ 
	int alreadyon; 
 
	alreadyon = floppy.motor & MOTORBIT(dp->dev); 
	floppy.motor |= MOTORBIT(dp->dev); 
	driveselect(dp); 
	if(!alreadyon) 
		tsleep(&dp->r, return0, 0, 750); 
	dp->lasttouched = m->ticks; 
} 
 
/* 
 *  stop the floppy if it hasn't been used in 5 seconds 
 */ 
static void 
motoroff(Drive *dp) 
{ 
	floppy.motor &= ~MOTORBIT(dp->dev); 
	driveselect(dp); 
} 
 
/* 
1991/0731    
 *  send a byte to the floppy 
 */ 
static int 
1991/0920/sys/src/9/pc/devfloppy.c:633,6411991/0921/sys/src/9/pc/devfloppy.c:646,654
1991/0727    
		outb(Fmotor, Fintena|Fena); 
		spllo(); 
1991/0809    
		for(dp = floppy.d; dp < &floppy.d[conf.nfloppy]; dp++){ 
1991/0727    
			dp->motoron = 0; 
			dp->confused = 1; 
		} 
1991/0921    
		floppy.motor = 0; 
1991/0731    
		sleep(&floppy.r, interrupted, 0); 
1991/0727    
		floppy.confused = 0; 
	} 
1991/0920/sys/src/9/pc/devfloppy.c:716,7231991/0921/sys/src/9/pc/devfloppy.c:729,735
1991/0727    
	 */ 
1991/0731    
	if(floppy.confused || dp->confused) 
		floppyrevive(); 
	if(!dp->motoron) 
		motoron(dp); 
1991/0921    
	motoron(dp); 
1991/0727    
 
1991/0731    
	/* 
	 *  calculate new position and seek to it (dp->len may be trimmed) 
1991/0921/sys/src/9/pc/devfloppy.c:6,411991/0924/sys/src/9/pc/devfloppy.c:6,47 (short | long)
1991/0727    
#include	"io.h" 
1991/0802    
#include	"errno.h" 
1991/0727    
 
1991/0920    
/* NEC PD765A (8272A compatible) floppy controller */ 
1991/0924    
/* Intel 82077A (8272A compatible) floppy controller */ 
1991/0920    
 
1991/0802    
typedef	struct Drive		Drive; 
1991/0727    
typedef	struct Controller	Controller; 
1991/0802    
typedef struct Type		Type; 
1991/0727    
 
1991/0924    
/* bits in the registers */ 
1991/0727    
enum 
{ 
	Fmotor=		0x3f2,	/* motor port */ 
	 Fintena=	 0x4,	/* enable floppy interrupt */ 
	 Fena=		 0x8,	/* 0 == reset controller */ 
1991/0924    
	/* digital output register */ 
	Pdor=		0x3f2, 
	Fintena=	0x8,	/* enable floppy interrupt */ 
	Fena=		0x4,	/* 0 == reset controller */ 
1991/0727    
 
	Fstatus=	0x3f4,	/* controller main status port */ 
	 Fready=	 0x80,	/* ready to be touched */ 
	 Ffrom=		 0x40,	/* data from controller */ 
	 Fbusy=		 0x10,	/* operation not over */ 
1991/0924    
	/* main status register */ 
	Pmsr=		0x3f4, 
	Fready=		0x80,	/* ready to be touched */ 
	Ffrom=		0x40,	/* data from controller */ 
	Fbusy=		0x10,	/* operation not over */ 
1991/0727    
 
	Fdata=		0x3f5,	/* controller data port */ 
	 Frecal=	 0x7,	/* recalibrate cmd */ 
	 Fseek=		 0xf,	/* seek cmd */ 
	 Fsense=	 0x8,	/* sense cmd */ 
	 Fread=		 0x66,	/* read cmd */ 
1991/0831    
	 Fwrite=	 0x45,	/* write cmd */ 
1991/0727    
	 Fmulti=	 0x80,	/* or'd with Fread or Fwrite for multi-head */ 
1991/0924    
	/* 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 */ 
	Fmulti=		0x80,	/* or'd with Fread or Fwrite for multi-head */ 
	Fdumpreg=	0x0e,	/* dump internal registers */ 
1991/0727    
 
1991/0831    
	Fchanged=	0x3F7,	/* disk changed register */ 
	 Fchange=	 0x80,	/* disk has changed */ 
1991/0924    
	/* digital input register */ 
	Pdir=		0x3F7,	/* disk changed port */ 
	Fchange=	0x80,	/* disk has changed */ 
1991/0831    
 
1991/0728    
	DMAchan=	2,	/* floppy dma channel */ 
                 
1991/0727    
	/* status 0 byte */ 
	Drivemask=	3<<0, 
	Seekend=	1<<5, 
1991/0921/sys/src/9/pc/devfloppy.c:46,511991/0924/sys/src/9/pc/devfloppy.c:52,59
1991/0802    
	Qdata=		(1<<2), 
1991/0920    
	Qctl=		(2<<2), 
1991/0802    
	Qmask=		(3<<2), 
1991/0924    
 
	DMAchan=	2,	/* floppy dma channel */ 
1991/0727    
}; 
 
/* 
1991/0921/sys/src/9/pc/devfloppy.c:68,781991/0924/sys/src/9/pc/devfloppy.c:76,88
1991/0731    
	 */ 
	int	bcode;		/* coded version of bytes for the controller */ 
1991/0727    
	long	cap;		/* drive capacity in bytes */ 
1991/0924    
	long	tsize;		/* track size in bytes */ 
1991/0727    
}; 
Type floppytype[] = 
{ 
1991/0731    
	{ "MF2HD",	512,	18,	2,	1,	80,	0x1B,	0x54, }, 
	{ "MF2DD",	512,	9,	2,	1,	80,	0x1B,	0x54, }, 
1991/0924    
	{ "MF1DD",	512,	9,	2,	1,	80,	0x1B,	0x54, }, 
	{ "MF4HD",	1024,	18,	2,	1,	80,	0x1B,	0x54, }, 
1991/0731    
	{ "F2HD",	512,	15,	2,	1,	80,	0x2A,	0x50, }, 
	{ "F2DD",	512,	8,	2,	2,	40,	0x2A,	0x50, }, 
	{ "F1DD",	512,	8,	1,	2,	40,	0x2A,	0x50, }, 
1991/0921/sys/src/9/pc/devfloppy.c:111,1171991/0924/sys/src/9/pc/devfloppy.c:121,127
1991/0727    
 
	ulong	lasttouched;	/* time last touched */ 
	int	cyl;		/* current cylinder */ 
	int	confused;	/* needs to be recalibrated (or worse) */ 
1991/0924    
	int	confused;	/* needs to be recalibrated */ 
1991/0727    
 
	int	tcyl;		/* target cylinder */ 
	int	thead;		/* target head */ 
1991/0921/sys/src/9/pc/devfloppy.c:118,1311991/0924/sys/src/9/pc/devfloppy.c:128,142
1991/0727    
	int	tsec;		/* target sector */ 
1991/0731    
	long	len;		/* size of xfer */ 
1991/0727    
 
1991/0731    
	Rendez	r;		/* waiting here for motor to spin up */ 
1991/0924    
	uchar	*cache;	/* track cache */ 
	int	ccyl; 
	int	chead; 
1991/0809    
 
	uchar	*ccache;	/* cylinder cache (always read a whole cyl) */ 
	int	ccyl;		/* number of cached cylinder */ 
1991/0924    
	Rendez	r;		/* waiting here for motor to spin up */ 
1991/0727    
}; 
 
/* 
 *  NEC PD765A controller for 4 floppys 
1991/0924    
 *  controller for 4 floppys 
1991/0727    
 */ 
struct Controller 
{ 
1991/0921/sys/src/9/pc/devfloppy.c:132,1471991/0924/sys/src/9/pc/devfloppy.c:143,159
1991/0731    
	QLock;			/* exclusive access to the contoller */ 
 
1991/0809    
	Drive	*d;		/* the floppy drives */ 
1991/0727    
	uchar	stat[8];	/* status of an operation */ 
	int	confused; 
1991/0731    
	int	intr;		/* true if interrupt occured */ 
1991/0924    
	uchar	cmd[14];	/* command */ 
	int	ncmd;		  /* # command bytes */ 
	uchar	stat[14];	/* command status */ 
	int	nstat;		  /* # status bytes */ 
	int	confused;	/* controler needs to be reset */ 
1991/0731    
	Rendez	r;		/* wait here for command termination */ 
1991/0921    
	int	motor; 
1991/0802    
                 
1991/0924    
	int	motor;		/* bit mask of spinning disks */ 
1991/0802    
	Rendez	kr;		/* for motor watcher */ 
1991/0727    
}; 
 
1991/0728    
Controller	floppy; 
1991/0924    
Controller	fl; 
1991/0727    
 
1991/0921    
#define MOTORBIT(i)	(1<<((i)+4)) 
 
1991/0921/sys/src/9/pc/devfloppy.c:148,1671991/0924/sys/src/9/pc/devfloppy.c:160,180
1991/0727    
/* 
1991/0731    
 *  predeclared 
 */ 
static void	motoron(Drive*); 
static void	motoroff(Drive*); 
1991/0924    
static int	floppycmd(void); 
static void	floppyeject(Drive*); 
1991/0731    
static void	floppykproc(void*); 
static int	floppysend(int); 
static int	floppyrcv(void); 
static int	floppyresult(int); 
1991/0924    
static void	floppyon(Drive*); 
static void	floppyoff(Drive*); 
1991/0802    
static void	floppypos(Drive*,long); 
1991/0731    
static int	floppysense(Drive*); 
static int	interrupted(void*); 
static int	floppyrecal(Drive*); 
1991/0924    
static int	floppyresult(void); 
1991/0731    
static void	floppyrevive(void); 
static long	floppyseek(Drive*); 
1991/0924    
static long	floppyseek(Drive*, long); 
static int	floppysense(void); 
static void	floppywait(void); 
1991/0802    
static long	floppyxfer(Drive*, int, void*, long, long); 
1991/0731    
static void	floppyintr(Ureg*); 
1991/0924    
static int	cmddone(void*); 
void Xdelay(int); 
1991/0731    
 
1991/0802    
Dirtab floppydir[]={ 
1991/0823    
	"fd0disk",		{Qdata + 0},	0,	0600, 
1991/0921/sys/src/9/pc/devfloppy.c:175,1811991/0924/sys/src/9/pc/devfloppy.c:188,193
1991/0802    
}; 
1991/0811    
#define NFDIR	2	/* directory entries/drive */ 
1991/0731    
 
1991/0809    
#define k64(x) (((ulong)(x))>>16) 
1991/0731    
void 
floppyreset(void) 
{ 
1991/0921/sys/src/9/pc/devfloppy.c:182,1871991/0924/sys/src/9/pc/devfloppy.c:194,201
1991/0731    
	Drive *dp; 
1991/0802    
	Type *t; 
1991/0810    
	int n; 
1991/0924    
	ulong p; 
	long l; 
1991/0731    
 
1991/0802    
	/* 
	 *  init dependent parameters 
1991/0921/sys/src/9/pc/devfloppy.c:189,2241991/0924/sys/src/9/pc/devfloppy.c:203,240
1991/0802    
	for(t = floppytype; t < &floppytype[NTYPES]; t++){ 
		t->cap = t->bytes * t->heads * t->sectors * t->tracks; 
		t->bcode = b2c[t->bytes/128]; 
1991/0924    
		t->tsize = t->bytes * t->sectors; 
1991/0802    
	} 
 
	/* 
1991/0809    
	 *  allocate the drive storage 
	 */ 
	floppy.d = ialloc(conf.nfloppy*sizeof(Drive), 0); 
1991/0924    
	fl.d = ialloc(conf.nfloppy*sizeof(Drive), 0); 
1991/0809    
 
	/* 
1991/0802    
	 *  stop the motors 
	 */ 
1991/0809    
	for(dp = floppy.d; dp < &floppy.d[conf.nfloppy]; dp++){ 
1991/0731    
		dp->dev = dp - floppy.d; 
1991/0924    
	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; 
1991/0731    
		dp->t = &floppytype[0];		/* default type */ 
1991/0811    
		floppydir[NFDIR*dp->dev].length = dp->t->cap; 
1991/0921    
		floppy.motor |= MOTORBIT(dp->dev); 
1991/0802    
		dp->cyl = -1;		/* because we don't know */ 
1991/0731    
		motoroff(dp); 
1991/0924    
		dp->cache = (uchar*)ialloc(dp->t->tsize, 1); 
		dp->ccyl = -1; 
1991/0731    
	} 
1991/0809    
 
	/* 
	 *  allocate cylinder caches that don't cross 64k boundaries 
1991/0924    
	 *  first operation will recalibrate 
1991/0809    
	 */ 
	for(dp = floppy.d; dp < &floppy.d[conf.nfloppy]; dp++){ 
		do { 
1991/0810    
			n = 512 * 18 * 2;	/* MF2HD cylinder size */ 
			dp->ccache = ialloc(n, 1); 
		} while(k64(dp->ccache) != k64(dp->ccache+n)); 
1991/0809    
		dp->ccyl = -1; 
	} 
1991/0731    
	setvec(Floppyvec, floppyintr); 
1991/0924    
	fl.confused = 1; 
1991/0731    
} 
 
void 
1991/0921/sys/src/9/pc/devfloppy.c:288,3801991/0924/sys/src/9/pc/devfloppy.c:304,419
1991/0802    
	error(Eperm); 
} 
 
1991/0809    
/* 
1991/0831    
 *  look for a floppy change 
 */ 
void 
1991/0902    
floppychanged(Drive *dp) 
1991/0831    
{ 
	if((inb(Fchanged) & Fchange) == 0) 
		return; 
                 
1991/0920    
	print("floppy has changed\n"); 
1991/0831    
} 
                 
/* 
1991/0809    
 *  the floppy is so slow, we always read a cylinder 
 *  at a time and cache the extra bytes. 
 */ 
1991/0731    
long 
floppyread(Chan *c, void *a, long n) 
{ 
	Drive *dp; 
1991/0809    
	long rv, nn, len, cyl; 
	int sec; 
1991/0731    
	uchar *aa = a; 
1991/0924    
	long rv, i; 
	int nn, sec, head, cyl; 
	long len; 
	long noff; 
	uchar *aa; 
1991/0731    
 
1991/0802    
	if(c->qid.path == CHDIR) 
1991/0811    
		return devdirread(c, a, n, floppydir, conf.nfloppy*NFDIR, devgen); 
1991/0802    
 
	rv = 0; 
	dp = &floppy.d[c->qid.path & ~Qmask]; 
1991/0924    
	dp = &fl.d[c->qid.path & ~Qmask]; 
 
1991/0802    
	switch ((int)(c->qid.path & Qmask)) { 
	case Qdata: 
1991/0831    
		floppychanged(dp); 
1991/0809    
		if(c->offset % dp->t->bytes) 
			errors("bad offset"); 
		if(n % dp->t->bytes) 
			errors("bad len"); 
		nn = dp->t->bytes * dp->t->sectors * dp->t->heads; 
1991/0924    
		aa = a; 
		nn = dp->t->tsize; 
1991/0809    
		for(rv = 0; rv < n; rv += len){ 
			/* 
			 *  truncate xfer at cylinder boundary 
1991/0924    
			 *  truncate xfer at track boundary 
1991/0809    
			 */ 
			dp->len = n - rv; 
			floppypos(dp, c->offset+rv); 
			cyl = dp->tcyl; 
1991/0924    
			head = dp->thead; 
1991/0809    
			len = dp->len; 
			sec = dp->tsec + dp->thead * dp->t->sectors; 
1991/0924    
			sec = dp->tsec; 
1991/0809    
 
			/* 
			 *  read the cylinder 
1991/0924    
			 *  read the track 
1991/0809    
			 */ 
			if(dp->ccyl != cyl){ 
1991/0924    
			if(dp->ccyl!=cyl || dp->chead!=head){ 
1991/0809    
				dp->ccyl = -1; 
				if(floppyxfer(dp, Fread, dp->ccache, cyl * nn, nn) != nn) 
1991/0924    
				i = floppyxfer(dp, Fread, dp->cache, 
					(cyl*dp->t->heads+head)*nn, nn); 
				if(i != nn){ 
					if(i == 0) 
						break; 
1991/0809    
					errors("floppy read err"); 
1991/0924    
				} 
1991/0809    
				dp->ccyl = cyl; 
1991/0924    
				dp->chead = head; 
1991/0809    
			} 
			memmove(aa+rv, dp->ccache + (sec-1)*dp->t->bytes, len); 
1991/0924    
			memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len); 
1991/0802    
		} 
		break; 
1991/0924    
	case Qctl: 
		break; 
1991/0802    
	default: 
		panic("floppyread: bad qid"); 
1991/0731    
	} 
1991/0924    
 
1991/0731    
	return rv; 
} 
 
1991/0924    
#define SNCMP(a, b) strncmp(a, b, sizeof(b)-1) 
1991/0731    
long 
floppywrite(Chan *c, void *a, long n) 
{ 
	Drive *dp; 
	long rv, i; 
	uchar *aa = a; 
1991/0924    
	char *aa = a; 
	int dev; 
1991/0731    
 
1991/0802    
	rv = 0; 
	dp = &floppy.d[c->qid.path & ~Qmask]; 
1991/0924    
	dp = &fl.d[c->qid.path & ~Qmask]; 
 
1991/0802    
	switch ((int)(c->qid.path & Qmask)) { 
	case Qdata: 
1991/0831    
		floppychanged(dp); 
		dp->ccyl = -1; 
1991/0924    
		if(c->offset % dp->t->bytes) 
			errors("bad offset"); 
		if(n % dp->t->bytes) 
			errors("bad len"); 
1991/0802    
		for(rv = 0; rv < n; rv += i){ 
			i = floppyxfer(dp, Fwrite, aa+rv, c->offset+rv, n-rv); 
1991/0924    
			floppypos(dp, c->offset+rv); 
			if(dp->tcyl == dp->ccyl) 
				dp->ccyl = -1; 
			i = floppyxfer(dp, Fwrite, aa+rv, c->offset+rv, 
				n-rv); 
1991/0802    
			if(i <= 0) 
				break; 
		} 
		break; 
1991/0924    
	case Qctl: 
		if(SNCMP(aa, "eject") == 0){ 
			floppyeject(dp); 
		} else if(SNCMP(aa, "seek") == 0){ 
			aa += 5; 
			floppyseek(dp, strtoul(aa, 0, 0)); 
		} else if(SNCMP(aa, "den") == 0){ 
			aa += 4; 
			i = strtoul(aa, 0, 0); 
			USED(i); 
/*			devp->dsr = i; 
			devp->ccr = i;/**/ 
		} else if(SNCMP(aa, "reset") == 0){ 
			floppyon(dp); 
		} 
		break; 
1991/0802    
	default: 
		panic("floppywrite: bad qid"); 
1991/0731    
	} 
1991/0924    
 
1991/0731    
	return rv; 
} 
 
1991/0921/sys/src/9/pc/devfloppy.c:382,4341991/0924/sys/src/9/pc/devfloppy.c:421,473
1991/0731    
floppykproc(void *a) 
1991/0727    
{ 
	Drive *dp; 
1991/0803    
	int disp = 0; 
1991/0924    
int i; 
static int last; 
1991/0727    
 
1991/0919    
	while(waserror()) 
		; 
1991/0802    
	for(;;){ 
1991/0809    
		for(dp = floppy.d; dp < &floppy.d[conf.nfloppy]; dp++){ 
1991/0921    
			if((floppy.motor&MOTORBIT(dp->dev)) 
1991/0924    
i = inb(Pdir) & 0x80; 
if(i != last) 
	print("fromn %d to %d\n", last, i); 
last = i; 
		for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++){ 
			if((fl.motor&MOTORBIT(dp->dev)) 
1991/0921    
			&& TK2SEC(m->ticks - dp->lasttouched) > 5 
1991/0802    
			&& canqlock(dp)){ 
				if(TK2SEC(m->ticks - dp->lasttouched) > 5) 
					motoroff(dp); 
1991/0924    
					floppyoff(dp); 
1991/0802    
				qunlock(dp); 
			} 
1991/0728    
		} 
1991/0803    
		disp++; 
1991/0802    
		tsleep(&floppy.kr, return0, 0, 5*1000); 
1991/0803    
		                 
1991/0924    
		tsleep(&fl.kr, return0, 0, 5*100); 
1991/0727    
	} 
} 
 
1991/0921    
static void 
driveselect(Drive *dp) 
{ 
	int cmd; 
                 
	cmd = floppy.motor | Fintena | Fena | dp->dev; 
	outb(Fmotor, cmd); 
} 
                 
1991/0731    
/* 
1991/0921    
 *  start a floppy drive's motor.  set an alarm for .75 second later to 
 *  mark it as started (we get no interrupt to tell us). 
 * 
 *  assume the caller qlocked the drive. 
 * 
 *  this also selects the drive for subsequent operations 
1991/0924    
 *  start a floppy drive's motor. 
1991/0921    
 */ 
static void 
motoron(Drive *dp) 
1991/0924    
floppyon(Drive *dp) 
1991/0921    
{ 
	int alreadyon; 
1991/0924    
	int tries; 
1991/0921    
 
	alreadyon = floppy.motor & MOTORBIT(dp->dev); 
	floppy.motor |= MOTORBIT(dp->dev); 
	driveselect(dp); 
1991/0924    
	if(fl.confused) 
		floppyrevive(); 
 
	/* start motor and select drive */ 
	alreadyon = fl.motor & MOTORBIT(dp->dev); 
	fl.motor |= MOTORBIT(dp->dev); 
	outb(Pdor, fl.motor | Fintena | Fena | dp->dev); 
1991/0921    
	if(!alreadyon) 
		tsleep(&dp->r, return0, 0, 750); 
1991/0924    
 
	/* get drive to a known cylinder */ 
	if(dp->confused) 
		for(tries = 0; tries < 4; tries++) 
			if(floppyrecal(dp) >= 0) 
				break; 
1991/0921    
	dp->lasttouched = m->ticks; 
} 
 
1991/0921/sys/src/9/pc/devfloppy.c:436,5841991/0924/sys/src/9/pc/devfloppy.c:475,613
1991/0921    
 *  stop the floppy if it hasn't been used in 5 seconds 
 */ 
static void 
motoroff(Drive *dp) 
1991/0924    
floppyoff(Drive *dp) 
1991/0921    
{ 
	floppy.motor &= ~MOTORBIT(dp->dev); 
	driveselect(dp); 
1991/0924    
	fl.motor &= ~MOTORBIT(dp->dev); 
	outb(Pdor, fl.motor | Fintena | Fena | dp->dev); 
1991/0921    
} 
 
/* 
1991/0731    
 *  send a byte to the floppy 
1991/0924    
 *  eject disk ( unknown on safari ) 
1991/0731    
 */ 
static int 
1991/0727    
floppysend(int data) 
1991/0924    
static void 
floppyeject(Drive *dp) 
1991/0727    
{ 
	int tries; 
	uchar c; 
                 
	for(tries = 0; tries < 100; tries++){ 
		/* 
		 *  see if its ready for data 
		 */ 
		c = inb(Fstatus); 
		if((c&(Ffrom|Fready)) != Fready) 
			continue; 
                 
		/* 
		 *  send the data 
		 */ 
		outb(Fdata, data); 
		return 0; 
	} 
	return -1; 
1991/0924    
	floppyon(dp); 
	floppyoff(dp); 
1991/0727    
} 
 
1991/0731    
/* 
 *  get a byte from the floppy 
1991/0924    
 *  send a command to the floppy 
1991/0731    
 */ 
static int 
1991/0727    
floppyrcv(void) 
1991/0924    
floppycmd(void) 
1991/0727    
{ 
1991/0924    
	int i; 
1991/0727    
	int tries; 
	uchar c; 
 
	for(tries = 0; tries < 100; tries++){ 
		/* 
		 *  see if its ready for data 
		 */ 
		c = inb(Fstatus); 
		if((c&(Ffrom|Fready)) != (Ffrom|Fready)) 
			continue; 
                 
		/* 
		 *  get data 
		 */ 
		return inb(Fdata)&0xff; 
1991/0924    
	for(i = 0; i < fl.ncmd; i++){ 
		for(tries = 0; ; tries++){ 
			if(tries > 1000){ 
print("cmd %ux can't be sent (%d %ux)\n", fl.cmd[0], i, inb(Pmsr)); 
				fl.confused = 1; 
				return -1; 
			} 
			if((inb(Pmsr)&(Ffrom|Fready)) == Fready) 
				break; 
		} 
		outb(Pdata, fl.cmd[i]); 
1991/0727    
	} 
	return -1; 
1991/0924    
	return 0; 
1991/0727    
} 
 
1991/0731    
/* 
 *  read a command result message from the floppy 
1991/0924    
 *  get a command result from the floppy 
 * 
 *  when the controller goes ready waiting for a command 
 *  (instead of sending results), we're done 
 *  
1991/0731    
 */ 
static int 
floppyresult(int n) 
1991/0924    
floppyresult(void) 
1991/0727    
{ 
	int i; 
	int c; 
1991/0924    
	int i, s; 
	int tries; 
1991/0727    
 
	for(i = 0; i < n; i++){ 
		c = floppyrcv(); 
		if(c < 0) 
			return -1; 
		floppy.stat[i] = c; 
1991/0924    
	for(i = 0; i < sizeof(fl.stat); i++){ 
		for(tries = 0; ; tries++){ 
			if(tries > 1000){ 
				fl.confused = 1; 
				return -1; 
			} 
			s = inb(Pmsr)&(Ffrom|Fready); 
			if(s == Fready){ 
				fl.nstat = i; 
				return i; 
			} 
			if(s == (Ffrom|Fready)) 
				break; 
		} 
		fl.stat[i] = inb(Pdata); 
1991/0727    
	} 
	return 0; 
1991/0924    
	fl.nstat = i; 
	return i; 
1991/0727    
} 
 
1991/0731    
/* 
 *  calculate physical address of a logical byte offset into the disk 
 * 
 *  truncate dp->length if it crosses a cylinder boundary 
1991/0924    
 *  truncate dp->length if it crosses a track boundary 
1991/0731    
 */ 
static void 
1991/0802    
floppypos(Drive *dp, long off) 
1991/0727    
{ 
	int lsec; 
1991/0924    
	int ltrack; 
1991/0727    
	int end; 
	int cyl; 
1991/0924    
	int track; 
1991/0727    
 
1991/0802    
	lsec = off/dp->t->bytes; 
1991/0727    
	dp->tcyl = lsec/(dp->t->sectors*dp->t->heads); 
1991/0924    
	ltrack = lsec/dp->t->sectors; 
	dp->tcyl = ltrack/dp->t->heads; 
1991/0727    
	dp->tsec = (lsec % dp->t->sectors) + 1; 
	dp->thead = (lsec/dp->t->sectors) % dp->t->heads; 
 
	/* 
	 *  can't read across cylinder boundaries. 
1991/0924    
	 *  can't read across track boundaries. 
1991/0727    
	 *  if so, decrement the bytes to be read. 
	 */ 
1991/0802    
	lsec = (off+dp->len)/dp->t->bytes; 
1991/0727    
	cyl = lsec/(dp->t->sectors*dp->t->heads); 
	if(cyl != dp->tcyl){ 
1991/0731    
		dp->len -= (lsec % dp->t->sectors)*dp->t->bytes; 
		dp->len -= ((lsec/dp->t->sectors) % dp->t->heads)*dp->t->bytes 
1991/0727    
				*dp->t->sectors; 
	} 
1991/0924    
	end = (ltrack+1)*dp->t->sectors*dp->t->bytes; 
	if(off+dp->len > end) 
		dp->len = end - off; 
1991/0727    
} 
 
1991/0731    
/* 
 *  get the interrupt cause from the floppy.  we need to do this 
 *  after seeks and recalibrations since they don't return results. 
1991/0924    
 *  get the interrupt cause from the floppy. 
1991/0731    
 */ 
static int 
1991/0727    
floppysense(Drive *dp) 
1991/0924    
floppysense(void) 
1991/0727    
{ 
	/* 
	 *  ask for floppy status 
	 */ 
	if(floppysend(Fsense) < 0){ 
		floppy.confused = 1; 
1991/0924    
	fl.ncmd = 0; 
	fl.cmd[fl.ncmd++] = Fsense; 
	if(floppycmd() < 0) 
1991/0727    
		return -1; 
	} 
1991/0731    
	if(floppyresult(2) < 0){ 
1991/0727    
		floppy.confused = 1; 
		dp->confused = 1; 
1991/0924    
	if(floppyresult() < 2){ 
print("can't read sense response\n"); 
		fl.confused = 1; 
1991/0727    
		return -1; 
	} 
                 
	/* 
	 *  make sure it's the right drive 
	 */ 
1991/0802    
	if((floppy.stat[0] & Drivemask) != dp->dev){ 
1991/0727    
		print("sense failed\n"); 
		dp->confused = 1; 
		return -1; 
	} 
	return 0; 
} 
 
1991/0924    
static int 
cmddone(void *a) 
{ 
	return fl.ncmd == 0; 
} 
 
1991/0731    
/* 
 *  return true if interrupt occurred 
1991/0924    
 *  wait for a floppy interrupt 
1991/0731    
 */ 
static int 
interrupted(void *a) 
1991/0924    
static void 
floppywait(void) 
1991/0731    
{ 
	return floppy.intr; 
1991/0924    
	tsleep(&fl.r, cmddone, 0, 2000); 
1991/0731    
} 
 
/* 
1991/0921/sys/src/9/pc/devfloppy.c:587,6211991/0924/sys/src/9/pc/devfloppy.c:616,641
1991/0731    
static int 
1991/0727    
floppyrecal(Drive *dp) 
{ 
	floppy.intr = 0; 
	if(floppysend(Frecal) < 0 
	|| floppysend(dp - floppy.d) < 0){ 
		floppy.confused = 0; 
		return -1; 
	} 
1991/0731    
	sleep(&floppy.r, interrupted, 0); 
1991/0924    
	int type; 
1991/0727    
 
	/* 
	 *  get return values 
	 */ 
	if(floppysense(dp) < 0) 
		return -1; 
1991/0924    
	dp->ccyl = -1; 
1991/0727    
 
	/* 
	 *  see if it worked 
	 */ 
	if((floppy.stat[0] & (Codemask|Seekend)) != Seekend){ 
		print("recalibrate failed\n"); 
1991/0924    
	fl.ncmd = 0; 
	fl.cmd[fl.ncmd++] = Frecal; 
	fl.cmd[fl.ncmd++] = dp->dev; 
	if(floppycmd() < 0) 
		return -1; 
	floppywait(); 
	if(fl.nstat < 2){ 
		fl.confused = 1; 
		return -1; 
	} 
	if((fl.stat[0] & (Codemask|Seekend)) != Seekend){ 
1991/0727    
		dp->confused = 1; 
		return -1; 
	} 
                 
	/* 
	 *  see what cylinder we got to 
	 */ 
	dp->tcyl = 0; 
	dp->cyl = floppy.stat[1]/dp->t->steps; 
	if(dp->cyl != dp->tcyl){ 
1991/0924    
	dp->cyl = fl.stat[1]/dp->t->steps; 
	if(dp->cyl != 0){ 
1991/0727    
		print("recalibrate went to wrong cylinder %d\n", dp->cyl); 
		dp->confused = 1; 
		return -1; 
1991/0921/sys/src/9/pc/devfloppy.c:635,7141991/0924/sys/src/9/pc/devfloppy.c:655,714
1991/0727    
	Drive *dp; 
 
	/* 
1991/0731    
	 *  reset the floppy if it's confused 
1991/0924    
	 *  reset the controller if it's confused 
1991/0727    
	 */ 
	if(floppy.confused){ 
1991/0924    
	if(fl.confused){ 
1991/0727    
		/* reset controller and turn all motors off */ 
		floppy.intr = 0; 
		splhi(); 
		outb(Fmotor, 0); 
1991/0924    
		fl.cmd[0] = 0; 
		outb(Pdor, 0); 
1991/0727    
		delay(1); 
		outb(Fmotor, Fintena|Fena); 
1991/0924    
		outb(Pdor, Fintena|Fena); 
1991/0727    
		spllo(); 
1991/0809    
		for(dp = floppy.d; dp < &floppy.d[conf.nfloppy]; dp++){ 
1991/0924    
		for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++) 
1991/0727    
			dp->confused = 1; 
		} 
1991/0921    
		floppy.motor = 0; 
1991/0731    
		sleep(&floppy.r, interrupted, 0); 
1991/0727    
		floppy.confused = 0; 
1991/0924    
		fl.motor = 0; 
		floppywait(); 
		fl.confused = 0; 
/*		devp->dsr = 0; 
		devp->ccr = 0; /**/ 
1991/0727    
	} 
                 
	/* 
	 *  recalibrate any confused drives 
	 */ 
1991/0809    
	for(dp = floppy.d; floppy.confused == 0 && dp < &floppy.d[conf.nfloppy]; dp++){ 
1991/0727    
		if(dp->confused == 0) 
			floppyrecal(dp); 
                 
	} 
                 
} 
 
1991/0924    
/* 
 *  seek to the target cylinder 
 * 
 *	interrupt, no results 
 */ 
1991/0731    
static long 
floppyseek(Drive *dp) 
1991/0924    
floppyseek(Drive *dp, long off) 
1991/0727    
{ 
1991/0924    
	floppyon(dp); 
	floppypos(dp, off); 
1991/0802    
	if(dp->cyl == dp->tcyl) 
		return dp->cyl; 
1991/0727    
 
	/* 
	 *  tell floppy to seek 
	 */ 
1991/0802    
	floppy.intr = 0; 
	dp->cyl = -1;	/* once the seek starts it could end anywhere */ 
1991/0727    
	if(floppysend(Fseek) < 0 
1991/0731    
	|| floppysend((dp->thead<<2) | dp->dev) < 0 
1991/0727    
	|| floppysend(dp->tcyl * dp->t->steps) < 0){ 
1991/0924    
/* print("seeking tcyl %d, thead %d\n", dp->tcyl, dp->thead); /**/ 
	fl.ncmd = 0; 
	fl.cmd[fl.ncmd++] = Fseek; 
	fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev; 
	fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps; 
	if(floppycmd() < 0){ 
1991/0727    
		print("seek cmd failed\n"); 
		floppy.confused = 1; 
		return -1; 
	} 
1991/0731    
	sleep(&floppy.r, interrupted, 0); 
1991/0727    
                 
	/* 
	 *  get floppy status 
	 */ 
	if(floppysense(dp) < 0) 
1991/0924    
	floppywait(); 
	if(fl.nstat < 2){ 
		fl.confused = 1; 
1991/0727    
		return -1; 
                 
	/* 
 	 *  see if it worked 
	 */ 
	if((floppy.stat[0] & (Codemask|Seekend)) != Seekend){ 
1991/0924    
	} 
	if((fl.stat[0] & (Codemask|Seekend)) != Seekend){ 
1991/0727    
		print("seek failed\n"); 
		dp->confused = 1; 
		return -1; 
	} 
 
	/* 
	 *  see what cylinder we got to 
	 */ 
	dp->cyl = floppy.stat[1]/dp->t->steps; 
	if(dp->cyl != dp->tcyl){ 
		print("seek went to wrong cylinder %d instead of %d\n", dp->cyl, dp->tcyl); 
		dp->confused = 1; 
		return -1; 
	} 
                 
1991/0924    
	dp->cyl = dp->tcyl; 
1991/0802    
	return dp->cyl; 
1991/0727    
} 
 
1991/0921/sys/src/9/pc/devfloppy.c:716,8001991/0924/sys/src/9/pc/devfloppy.c:716,812
1991/0802    
floppyxfer(Drive *dp, int cmd, void *a, long off, long n) 
1991/0727    
{ 
	long offset; 
1991/0924    
	ulong up; 
1991/0727    
 
1991/0731    
	qlock(&floppy); 
1991/0924    
	if(off >= dp->t->cap) 
		return 0; 
	if(off + n > dp->t->cap) 
		n = dp->t->cap - off; 
 
	qlock(&fl); 
1991/0731    
	qlock(dp); 
1991/0802    
	if(waserror()){ 
1991/0731    
		qunlock(&floppy); 
1991/0924    
		dmaend(DMAchan); 
		qunlock(&fl); 
1991/0731    
		qunlock(dp); 
1991/0924    
		fl.confused = 1; 
		nexterror(); 
1991/0731    
	} 
 
1991/0727    
	/* 
1991/0731    
	 *  get floppy reset and spinning 
1991/0727    
	 */ 
1991/0731    
	if(floppy.confused || dp->confused) 
		floppyrevive(); 
1991/0921    
	motoron(dp); 
1991/0727    
                 
1991/0731    
	/* 
	 *  calculate new position and seek to it (dp->len may be trimmed) 
	 */ 
1991/0727    
	dp->len = n; 
1991/0802    
	floppypos(dp, off); 
1991/0731    
	if(floppyseek(dp) < 0) 
1991/0924    
	if(floppyseek(dp, off) < 0) 
1991/0731    
		errors("seeking floppy"); 
1991/0727    
                 
1991/0906    
	 
1991/0823    
/*print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n", 
1991/0906    
		dp->tcyl, dp->thead, dp->tsec, a, n);/**/ 
1991/0924    
	dp->tcyl, dp->thead, dp->tsec, a, dp->len);/**/ 
1991/0727    
 
	/* 
1991/0731    
	 *  set up the dma (dp->len may be trimmed) 
1991/0727    
	 */ 
1991/0731    
	dp->len = dmasetup(2, a, dp->len, cmd==Fread); 
1991/0924    
	dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread); 
1991/0727    
 
	/* 
1991/0731    
	 *  start operation 
1991/0727    
	 */ 
1991/0802    
	floppy.intr = 0; 
1991/0727    
	cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0); 
	if(floppysend(cmd) < 0 
1991/0802    
	|| floppysend((dp->thead<<2) | dp->dev) < 0 
1991/0727    
	|| floppysend(dp->tcyl * dp->t->steps) < 0 
	|| floppysend(dp->thead) < 0 
	|| floppysend(dp->tsec) < 0 
1991/0731    
	|| floppysend(dp->t->bcode) < 0 
1991/0727    
	|| floppysend(dp->t->sectors) < 0 
	|| floppysend(dp->t->gpl) < 0 
	|| floppysend(0xFF) < 0){ 
1991/0924    
/*	cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0);/**/ 
	fl.ncmd = 0; 
	fl.cmd[fl.ncmd++] = cmd; 
	fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev; 
	fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps; 
	fl.cmd[fl.ncmd++] = dp->thead; 
	fl.cmd[fl.ncmd++] = dp->tsec; 
	fl.cmd[fl.ncmd++] = dp->t->bcode; 
	fl.cmd[fl.ncmd++] = dp->tsec + dp->len/dp->t->bytes - 1; 
	fl.cmd[fl.ncmd++] = dp->t->gpl; 
	fl.cmd[fl.ncmd++] = 0xFF; 
	if(floppycmd() < 0){ 
		spllo(); 
1991/0727    
		print("xfer cmd failed\n"); 
		floppy.confused = 1; 
1991/0731    
		errors("floppy command failed"); 
1991/0727    
	} 
1991/0731    
	sleep(&floppy.r, interrupted, 0); 
1991/0727    
 
	/* 
	 *  get status 
 	 */ 
1991/0731    
	if(floppyresult(7) < 0){ 
print("xfer status failed\n"); 
1991/0727    
		floppy.confused = 1; 
1991/0924    
	 *  give bus to DMA, floppyintr() will read result 
	 */ 
	floppywait(); 
	dmaend(DMAchan); 
 
	/* 
	 *  check for errors 
	 */ 
	if(fl.nstat < 7){ 
		print("xfer result failed %lux\n", inb(Pmsr)); 
		fl.confused = 1; 
1991/0731    
		errors("floppy result failed"); 
1991/0727    
	} 
                 
	if((floppy.stat[0] & Codemask)!=0 || floppy.stat[1] || floppy.stat[2]){ 
print("xfer failed %lux %lux %lux\n", floppy.stat[0], 
			floppy.stat[1], floppy.stat[2]); 
		dp->confused = 1; 
1991/0731    
		errors("floppy drive lost"); 
1991/0924    
	if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){ 
		if(fl.stat[1] != 0x80){ 
			print("xfer failed %lux %lux %lux\n", fl.stat[0], 
				fl.stat[1], fl.stat[2]); 
			print("offset %lud len %d\n", off, dp->len); 
			dp->confused = 1; 
			errors("floppy drive lost"); 
		} else 
			fl.stat[5]++; 
1991/0727    
	} 
 
	offset = (floppy.stat[3]/dp->t->steps) * dp->t->heads + floppy.stat[4]; 
	offset = offset*dp->t->sectors + floppy.stat[5] - 1; 
1991/0731    
	offset = offset * c2b[floppy.stat[6]]; 
1991/0924    
	/* 
	 *  check for correct cylinder 
	 */ 
	offset = (fl.stat[3]/dp->t->steps) * dp->t->heads + fl.stat[4]; 
	offset = offset*dp->t->sectors + fl.stat[5] - 1; 
	offset = offset * c2b[fl.stat[6]]; 
1991/0802    
	if(offset != off+dp->len){ 
print("new offset %d instead of %d\n", offset, off+dp->len); 
1991/0924    
		print("new offset %d instead of %d\n", offset, off+dp->len); 
1991/0727    
		dp->confused = 1; 
1991/0731    
		errors("floppy drive lost"); 
1991/0727    
	} 
 
1991/0802    
	dp->lasttouched = m->ticks; 
1991/0731    
	qunlock(&floppy); 
1991/0924    
	qunlock(&fl); 
1991/0731    
	qunlock(dp); 
	poperror(); 
 
1991/0921/sys/src/9/pc/devfloppy.c:801,8101991/0924/sys/src/9/pc/devfloppy.c:813,835
1991/0727    
	return dp->len; 
} 
 
1991/0731    
static void 
1991/0727    
floppyintr(Ureg *ur) 
1991/0924    
void 
floppyintr(void) 
1991/0727    
{ 
1991/0823    
/*print("floppy intr\n");/**/ 
1991/0727    
	floppy.intr = 1; 
1991/0731    
	wakeup(&floppy.r); 
1991/0924    
	switch(fl.cmd[0]&~Fmulti){ 
	case Fread: 
	case Fwrite: 
		floppyresult(); 
		break; 
	case Freadid: 
		floppyresult(); 
		break; 
	case Fseek: 
	case Frecal: 
	default: 
		floppysense();	/* to clear interrupt */ 
		break; 
	} 
	fl.ncmd = 0; 
	wakeup(&fl.r); 
1991/0727    
} 
1991/0924/sys/src/9/pc/devfloppy.c:39,451991/0925/sys/src/9/pc/devfloppy.c:39,46 (short | long)
1991/0924    
	Fdumpreg=	0x0e,	/* dump internal registers */ 
1991/0727    
 
1991/0924    
	/* digital input register */ 
	Pdir=		0x3F7,	/* disk changed port */ 
1991/0925    
	Pdir=		0x3F7,	/* disk changed port (read only) */ 
	Pdsr=		0x3F7,	/* data rate select port (write only) */ 
1991/0924    
	Fchange=	0x80,	/* disk has changed */ 
1991/0831    
 
1991/0727    
	/* status 0 byte */ 
1991/0924/sys/src/9/pc/devfloppy.c:114,1211991/0925/sys/src/9/pc/devfloppy.c:115,120
1991/0727    
 */ 
struct Drive 
{ 
1991/0731    
	QLock;			/* exclusive access to the drive */ 
                 
1991/0727    
	Type	*t; 
	int	dev; 
 
1991/0924/sys/src/9/pc/devfloppy.c:122,1271991/0925/sys/src/9/pc/devfloppy.c:121,127
1991/0727    
	ulong	lasttouched;	/* time last touched */ 
	int	cyl;		/* current cylinder */ 
1991/0924    
	int	confused;	/* needs to be recalibrated */ 
1991/0925    
	int	vers; 
1991/0727    
 
	int	tcyl;		/* target cylinder */ 
	int	thead;		/* target head */ 
1991/0924/sys/src/9/pc/devfloppy.c:143,1481991/0925/sys/src/9/pc/devfloppy.c:143,149
1991/0731    
	QLock;			/* exclusive access to the contoller */ 
 
1991/0809    
	Drive	*d;		/* the floppy drives */ 
1991/0925    
	Drive	*selected; 
1991/0924    
	uchar	cmd[14];	/* command */ 
	int	ncmd;		  /* # command bytes */ 
	uchar	stat[14];	/* command status */ 
1991/0924/sys/src/9/pc/devfloppy.c:162,1671991/0925/sys/src/9/pc/devfloppy.c:163,169
1991/0731    
 */ 
1991/0924    
static int	floppycmd(void); 
static void	floppyeject(Drive*); 
1991/0925    
static void	floppyintr(Ureg*); 
1991/0731    
static void	floppykproc(void*); 
1991/0924    
static void	floppyon(Drive*); 
static void	floppyoff(Drive*); 
1991/0924/sys/src/9/pc/devfloppy.c:210,2151991/0925/sys/src/9/pc/devfloppy.c:212,218
1991/0809    
	 *  allocate the drive storage 
	 */ 
1991/0924    
	fl.d = ialloc(conf.nfloppy*sizeof(Drive), 0); 
1991/0925    
	fl.selected = fl.d; 
1991/0809    
 
	/* 
1991/0802    
	 *  stop the motors 
1991/0924/sys/src/9/pc/devfloppy.c:229,2341991/0925/sys/src/9/pc/devfloppy.c:232,238
1991/0802    
		dp->cyl = -1;		/* because we don't know */ 
1991/0924    
		dp->cache = (uchar*)ialloc(dp->t->tsize, 1); 
		dp->ccyl = -1; 
1991/0925    
		dp->vers = 1; 
1991/0731    
	} 
1991/0809    
 
	/* 
1991/0924/sys/src/9/pc/devfloppy.c:235,2401991/0925/sys/src/9/pc/devfloppy.c:239,245
1991/0924    
	 *  first operation will recalibrate 
1991/0809    
	 */ 
1991/0924    
	fl.confused = 1; 
1991/0925    
	setvec(Floppyvec, floppyintr); 
1991/0731    
} 
 
void 
1991/0924/sys/src/9/pc/devfloppy.c:278,2841991/0925/sys/src/9/pc/devfloppy.c:283,289
1991/0802    
Chan* 
floppyopen(Chan *c, int omode) 
{ 
1991/0811    
	return devopen(c, omode, floppydir, conf.nfloppy*NFDIR, devgen); 
1991/0925    
	devopen(c, omode, floppydir, conf.nfloppy*NFDIR, devgen); 
1991/0802    
} 
 
void 
1991/0924/sys/src/9/pc/devfloppy.c:304,3091991/0925/sys/src/9/pc/devfloppy.c:309,348
1991/0802    
	error(Eperm); 
} 
 
1991/0925    
static void 
islegal(Chan *c, long n, Drive *dp) 
{ 
	if(c->offset % dp->t->bytes) 
		errors("bad offset"); 
	if(n % dp->t->bytes) 
		errors("bad len"); 
} 
 
/* 
 *  check if the floppy has been replaced under foot 
 * 
 *  a seek and a read clears the condition.  this was determined experimentally, 
 *  there has to be a better way. 
 */ 
static void 
changed(Chan *c, Drive *dp) 
{ 
	ulong old; 
 
	if(inb(Pdir)&Fchange) 
		dp->vers++; 
	old = c->qid.vers; 
	c->qid.vers = dp->vers; 
	if(old && old!=dp->vers){ 
		dp->ccyl = -1; 
		if(dp->cyl) 
			floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize); 
		else 
			floppyxfer(dp, Fread, dp->cache, dp->t->heads*dp->t->tsize, dp->t->tsize); 
		errors("disk changed"); 
	} 
} 
 
1991/0731    
long 
floppyread(Chan *c, void *a, long n) 
{ 
1991/0924/sys/src/9/pc/devfloppy.c:319,3331991/0925/sys/src/9/pc/devfloppy.c:358,376
1991/0802    
 
	rv = 0; 
1991/0924    
	dp = &fl.d[c->qid.path & ~Qmask]; 
                 
1991/0802    
	switch ((int)(c->qid.path & Qmask)) { 
	case Qdata: 
1991/0809    
		if(c->offset % dp->t->bytes) 
			errors("bad offset"); 
		if(n % dp->t->bytes) 
			errors("bad len"); 
1991/0925    
		islegal(c, n, dp); 
1991/0924    
		aa = a; 
		nn = dp->t->tsize; 
1991/0925    
 
		qlock(&fl); 
		if(waserror()){ 
			qunlock(&fl); 
			nexterror(); 
		} 
		floppyon(dp); 
		changed(c, dp); 
1991/0809    
		for(rv = 0; rv < n; rv += len){ 
			/* 
1991/0924    
			 *  truncate xfer at track boundary 
1991/0924/sys/src/9/pc/devfloppy.c:356,3611991/0925/sys/src/9/pc/devfloppy.c:399,407
1991/0809    
			} 
1991/0924    
			memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len); 
1991/0802    
		} 
1991/0925    
		qunlock(&fl); 
		poperror(); 
 
1991/0802    
		break; 
1991/0924    
	case Qctl: 
		break; 
1991/0924/sys/src/9/pc/devfloppy.c:377,3891991/0925/sys/src/9/pc/devfloppy.c:423,438
1991/0731    
 
1991/0802    
	rv = 0; 
1991/0924    
	dp = &fl.d[c->qid.path & ~Qmask]; 
                 
1991/0802    
	switch ((int)(c->qid.path & Qmask)) { 
	case Qdata: 
1991/0924    
		if(c->offset % dp->t->bytes) 
			errors("bad offset"); 
		if(n % dp->t->bytes) 
			errors("bad len"); 
1991/0925    
		islegal(c, n, dp); 
		qlock(&fl); 
		if(waserror()){ 
			qunlock(&fl); 
			nexterror(); 
		} 
		floppyon(dp); 
		changed(c, dp); 
1991/0802    
		for(rv = 0; rv < n; rv += i){ 
1991/0924    
			floppypos(dp, c->offset+rv); 
			if(dp->tcyl == dp->ccyl) 
1991/0924/sys/src/9/pc/devfloppy.c:393,4141991/0925/sys/src/9/pc/devfloppy.c:442,459
1991/0802    
			if(i <= 0) 
				break; 
		} 
1991/0925    
		qunlock(&fl); 
		poperror(); 
1991/0802    
		break; 
1991/0924    
	case Qctl: 
1991/0925    
		qlock(&fl); 
1991/0924    
		if(SNCMP(aa, "eject") == 0){ 
			floppyeject(dp); 
		} else if(SNCMP(aa, "seek") == 0){ 
			aa += 5; 
			floppyseek(dp, strtoul(aa, 0, 0)); 
		} else if(SNCMP(aa, "den") == 0){ 
			aa += 4; 
			i = strtoul(aa, 0, 0); 
			USED(i); 
/*			devp->dsr = i; 
			devp->ccr = i;/**/ 
		} else if(SNCMP(aa, "reset") == 0){ 
1991/0925    
			fl.confused = 1; 
1991/0924    
			floppyon(dp); 
		} 
1991/0925    
		qunlock(&fl); 
1991/0924    
		break; 
1991/0802    
	default: 
		panic("floppywrite: bad qid"); 
1991/0924/sys/src/9/pc/devfloppy.c:421,4461991/0925/sys/src/9/pc/devfloppy.c:466,485
1991/0731    
floppykproc(void *a) 
1991/0727    
{ 
	Drive *dp; 
1991/0924    
int i; 
static int last; 
1991/0727    
 
1991/0919    
	while(waserror()) 
		; 
1991/0802    
	for(;;){ 
1991/0924    
i = inb(Pdir) & 0x80; 
if(i != last) 
	print("fromn %d to %d\n", last, i); 
last = i; 
		for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++){ 
			if((fl.motor&MOTORBIT(dp->dev)) 
1991/0921    
			&& TK2SEC(m->ticks - dp->lasttouched) > 5 
1991/0802    
			&& canqlock(dp)){ 
1991/0925    
			&& canqlock(&fl)){ 
1991/0802    
				if(TK2SEC(m->ticks - dp->lasttouched) > 5) 
1991/0924    
					floppyoff(dp); 
1991/0802    
				qunlock(dp); 
1991/0925    
				qunlock(&fl); 
1991/0802    
			} 
1991/0728    
		} 
1991/0924    
		tsleep(&fl.kr, return0, 0, 5*100); 
1991/0925    
		tsleep(&fl.kr, return0, 0, 1000); 
1991/0727    
	} 
} 
 
1991/0924/sys/src/9/pc/devfloppy.c:469,4741991/0925/sys/src/9/pc/devfloppy.c:508,514
1991/0924    
			if(floppyrecal(dp) >= 0) 
				break; 
1991/0921    
	dp->lasttouched = m->ticks; 
1991/0925    
	fl.selected = dp; 
1991/0921    
} 
 
/* 
1991/0924/sys/src/9/pc/devfloppy.c:479,4841991/0925/sys/src/9/pc/devfloppy.c:519,525
1991/0921    
{ 
1991/0924    
	fl.motor &= ~MOTORBIT(dp->dev); 
	outb(Pdor, fl.motor | Fintena | Fena | dp->dev); 
1991/0925    
	fl.selected = dp; 
1991/0921    
} 
 
/* 
1991/0924/sys/src/9/pc/devfloppy.c:488,4931991/0925/sys/src/9/pc/devfloppy.c:529,535
1991/0924    
floppyeject(Drive *dp) 
1991/0727    
{ 
1991/0924    
	floppyon(dp); 
1991/0925    
	dp->vers++; 
1991/0924    
	floppyoff(dp); 
1991/0727    
} 
 
1991/0924/sys/src/9/pc/devfloppy.c:670,6771991/0925/sys/src/9/pc/devfloppy.c:712,718
1991/0924    
		fl.motor = 0; 
		floppywait(); 
		fl.confused = 0; 
/*		devp->dsr = 0; 
		devp->ccr = 0; /**/ 
1991/0925    
		outb(Pdsr, 0); 
1991/0727    
	} 
} 
 
1991/0924/sys/src/9/pc/devfloppy.c:683,6891991/0925/sys/src/9/pc/devfloppy.c:724,729
1991/0731    
static long 
1991/0924    
floppyseek(Drive *dp, long off) 
1991/0727    
{ 
1991/0924    
	floppyon(dp); 
	floppypos(dp, off); 
1991/0802    
	if(dp->cyl == dp->tcyl) 
		return dp->cyl; 
1991/0924/sys/src/9/pc/devfloppy.c:723,7381991/0925/sys/src/9/pc/devfloppy.c:763,768
1991/0924    
	if(off + n > dp->t->cap) 
		n = dp->t->cap - off; 
 
	qlock(&fl); 
1991/0731    
	qlock(dp); 
1991/0802    
	if(waserror()){ 
1991/0924    
		dmaend(DMAchan); 
		qunlock(&fl); 
1991/0731    
		qunlock(dp); 
1991/0924    
		fl.confused = 1; 
		nexterror(); 
1991/0731    
	} 
                 
1991/0727    
	/* 
1991/0731    
	 *  calculate new position and seek to it (dp->len may be trimmed) 
	 */ 
1991/0924/sys/src/9/pc/devfloppy.c:739,7451991/0925/sys/src/9/pc/devfloppy.c:769,775
1991/0727    
	dp->len = n; 
1991/0924    
	if(floppyseek(dp, off) < 0) 
1991/0731    
		errors("seeking floppy"); 
1991/0906    
	                 
1991/0925    
 
1991/0823    
/*print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n", 
1991/0924    
	dp->tcyl, dp->thead, dp->tsec, a, dp->len);/**/ 
1991/0727    
 
1991/0924/sys/src/9/pc/devfloppy.c:751,7571991/0925/sys/src/9/pc/devfloppy.c:781,787
1991/0727    
	/* 
1991/0731    
	 *  start operation 
1991/0727    
	 */ 
1991/0924    
/*	cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0);/**/ 
1991/0925    
	cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0); 
1991/0924    
	fl.ncmd = 0; 
	fl.cmd[fl.ncmd++] = cmd; 
	fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev; 
1991/0924/sys/src/9/pc/devfloppy.c:783,7961991/0925/sys/src/9/pc/devfloppy.c:813,823
1991/0731    
		errors("floppy result failed"); 
1991/0727    
	} 
1991/0924    
	if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){ 
		if(fl.stat[1] != 0x80){ 
			print("xfer failed %lux %lux %lux\n", fl.stat[0], 
				fl.stat[1], fl.stat[2]); 
			print("offset %lud len %d\n", off, dp->len); 
			dp->confused = 1; 
			errors("floppy drive lost"); 
		} else 
			fl.stat[5]++; 
1991/0925    
		print("xfer failed %lux %lux %lux\n", fl.stat[0], 
			fl.stat[1], fl.stat[2]); 
		print("offset %lud len %d\n", off, dp->len); 
		dp->confused = 1; 
		errors("floppy drive lost"); 
1991/0727    
	} 
 
1991/0924    
	/* 
1991/0924/sys/src/9/pc/devfloppy.c:801,8201991/0925/sys/src/9/pc/devfloppy.c:828,844
1991/0924    
	offset = offset * c2b[fl.stat[6]]; 
1991/0802    
	if(offset != off+dp->len){ 
1991/0924    
		print("new offset %d instead of %d\n", offset, off+dp->len); 
1991/0925    
		print("	%d %d %d\n", fl.stat[3], fl.stat[4], fl.stat[5]); 
1991/0727    
		dp->confused = 1; 
1991/0731    
		errors("floppy drive lost"); 
1991/0727    
	} 
 
1991/0802    
	dp->lasttouched = m->ticks; 
1991/0924    
	qunlock(&fl); 
1991/0731    
	qunlock(dp); 
	poperror(); 
                 
1991/0727    
	return dp->len; 
} 
 
1991/0924    
void 
floppyintr(void) 
1991/0925    
static void 
floppyintr(Ureg *ur) 
1991/0727    
{ 
1991/0924    
	switch(fl.cmd[0]&~Fmulti){ 
	case Fread: 
1991/0925/sys/src/9/pc/devfloppy.c:420,4251991/0927/sys/src/9/pc/devfloppy.c:420,426 (short | long)
1991/0731    
	long rv, i; 
1991/0924    
	char *aa = a; 
	int dev; 
1991/0927    
extern void vgaset(char*); 
1991/0731    
 
1991/0802    
	rv = 0; 
1991/0924    
	dp = &fl.d[c->qid.path & ~Qmask]; 
1991/0925/sys/src/9/pc/devfloppy.c:452,4571991/0927/sys/src/9/pc/devfloppy.c:453,460
1991/0924    
		} else if(SNCMP(aa, "reset") == 0){ 
1991/0925    
			fl.confused = 1; 
1991/0924    
			floppyon(dp); 
1991/0927    
		} else if(SNCMP(aa, "v") == 0){ 
			vgaset(aa+1); 
1991/0924    
		} 
1991/0925    
		qunlock(&fl); 
1991/0924    
		break; 
1991/0927/sys/src/9/pc/devfloppy.c:792,7981991/1001/sys/src/9/pc/devfloppy.c:792,798 (short | long)
1991/0924    
	fl.cmd[fl.ncmd++] = dp->thead; 
	fl.cmd[fl.ncmd++] = dp->tsec; 
	fl.cmd[fl.ncmd++] = dp->t->bcode; 
	fl.cmd[fl.ncmd++] = dp->tsec + dp->len/dp->t->bytes - 1; 
1991/1001    
	fl.cmd[fl.ncmd++] = dp->t->sectors; 
1991/0924    
	fl.cmd[fl.ncmd++] = dp->t->gpl; 
	fl.cmd[fl.ncmd++] = 0xFF; 
	if(floppycmd() < 0){ 
1991/1001/sys/src/9/pc/devfloppy.c:329,3461991/1003/sys/src/9/pc/devfloppy.c:329,346 (short | long)
1991/0925    
{ 
	ulong old; 
 
	if(inb(Pdir)&Fchange) 
1991/1003    
	if(inb(Pdir)&Fchange){ 
1991/0925    
		dp->vers++; 
	old = c->qid.vers; 
	c->qid.vers = dp->vers; 
	if(old && old!=dp->vers){ 
		dp->ccyl = -1; 
		if(dp->cyl) 
			floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize); 
		else 
			floppyxfer(dp, Fread, dp->cache, dp->t->heads*dp->t->tsize, dp->t->tsize); 
		errors("disk changed"); 
	} 
1991/1003    
	old = c->qid.vers; 
	c->qid.vers = dp->vers; 
	if(old && old!=dp->vers) 
		errors("disk changed"); 
1991/0925    
} 
 
1991/0731    
long 
1991/1003/sys/src/9/pc/devfloppy.c:633,6391991/1005/sys/src/9/pc/devfloppy.c:633,639 (short | long)
1991/0924    
	if(floppycmd() < 0) 
1991/0727    
		return -1; 
1991/0924    
	if(floppyresult() < 2){ 
print("can't read sense response\n"); 
1991/1005    
/*print("can't read sense response\n");/**/ 
1991/0924    
		fl.confused = 1; 
1991/0727    
		return -1; 
	} 
1991/1005/sys/src/9/pc/devfloppy.c:175,1801991/1006/sys/src/9/pc/devfloppy.c:175,181 (short | long)
1991/0924    
static int	floppysense(void); 
static void	floppywait(void); 
1991/0802    
static long	floppyxfer(Drive*, int, void*, long, long); 
1991/1006    
static long	floppythrice(Drive*, int, void*, long, long); 
1991/0924    
static int	cmddone(void*); 
void Xdelay(int); 
1991/0731    
 
1991/1005/sys/src/9/pc/devfloppy.c:387,3931991/1006/sys/src/9/pc/devfloppy.c:388,394
1991/0809    
			 */ 
1991/0924    
			if(dp->ccyl!=cyl || dp->chead!=head){ 
1991/0809    
				dp->ccyl = -1; 
1991/0924    
				i = floppyxfer(dp, Fread, dp->cache, 
1991/1006    
				i = floppythrice(dp, Fread, dp->cache, 
1991/0924    
					(cyl*dp->t->heads+head)*nn, nn); 
				if(i != nn){ 
					if(i == 0) 
1991/1005/sys/src/9/pc/devfloppy.c:420,4261991/1006/sys/src/9/pc/devfloppy.c:421,426
1991/0731    
	long rv, i; 
1991/0924    
	char *aa = a; 
	int dev; 
1991/0927    
extern void vgaset(char*); 
1991/0731    
 
1991/0802    
	rv = 0; 
1991/0924    
	dp = &fl.d[c->qid.path & ~Qmask]; 
1991/1005/sys/src/9/pc/devfloppy.c:438,4471991/1006/sys/src/9/pc/devfloppy.c:438,449
1991/0924    
			floppypos(dp, c->offset+rv); 
			if(dp->tcyl == dp->ccyl) 
				dp->ccyl = -1; 
			i = floppyxfer(dp, Fwrite, aa+rv, c->offset+rv, 
1991/1006    
			i = floppythrice(dp, Fwrite, aa+rv, c->offset+rv, 
1991/0924    
				n-rv); 
1991/0802    
			if(i <= 0) 
1991/1006    
			if(i < 0) 
1991/0802    
				break; 
1991/1006    
			if(i == 0) 
				error(Eio); 
1991/0802    
		} 
1991/0925    
		qunlock(&fl); 
		poperror(); 
1991/1005/sys/src/9/pc/devfloppy.c:453,4601991/1006/sys/src/9/pc/devfloppy.c:455,460
1991/0924    
		} else if(SNCMP(aa, "reset") == 0){ 
1991/0925    
			fl.confused = 1; 
1991/0924    
			floppyon(dp); 
1991/0927    
		} else if(SNCMP(aa, "v") == 0){ 
			vgaset(aa+1); 
1991/0924    
		} 
1991/0925    
		qunlock(&fl); 
1991/0924    
		break; 
1991/1005/sys/src/9/pc/devfloppy.c:755,7611991/1006/sys/src/9/pc/devfloppy.c:755,782
1991/0802    
	return dp->cyl; 
1991/0727    
} 
 
1991/1006    
/* 
 *  since floppies are so flakey, try 3 times before giving up 
 */ 
1991/0731    
static long 
1991/1006    
floppythrice(Drive *dp, int cmd, void *a, long off, long n) 
{ 
	int tries; 
	long rv; 
 
	for(tries = 0; ; tries++){ 
		if(waserror()){ 
			if(strcmp(u->error, errstrtab[Eintr])==0 || tries > 3) 
				nexterror(); 
		} else { 
			rv = floppyxfer(dp, cmd, a, off, n); 
			poperror(); 
			return rv; 
		} 
	} 
} 
 
static long 
1991/0802    
floppyxfer(Drive *dp, int cmd, void *a, long off, long n) 
1991/0727    
{ 
	long offset; 
1991/1005/sys/src/9/pc/devfloppy.c:830,8371991/1006/sys/src/9/pc/devfloppy.c:851,856
1991/0924    
	offset = offset*dp->t->sectors + fl.stat[5] - 1; 
	offset = offset * c2b[fl.stat[6]]; 
1991/0802    
	if(offset != off+dp->len){ 
1991/0924    
		print("new offset %d instead of %d\n", offset, off+dp->len); 
1991/0925    
		print("	%d %d %d\n", fl.stat[3], fl.stat[4], fl.stat[5]); 
1991/0727    
		dp->confused = 1; 
1991/0731    
		errors("floppy drive lost"); 
1991/0727    
	} 
Too many diffs (26 > 25). Stopping.


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)