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

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

1991/0730/sys/src/9/pc/devfloppy.c:29,351991/0731/sys/src/9/pc/devfloppy.c:29,35 (short | long | prev | next)
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    
} 


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