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

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

1991/0731/sys/src/9/pc/devfloppy.c:4,141991/0802/sys/src/9/pc/devfloppy.c:4,14 (short | long | prev | next)
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; 
} 
 


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