⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 devfloppy.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
		timedsleep(return0, 0, 750);		/* clear any pending interrupts */		floppysense();	}	/* set transfer rate */	if(fl.rate != dp->t->rate){		fl.rate = dp->t->rate;		outb(Pdsr, fl.rate);	}	/* get drive to a known cylinder */	if(dp->confused)		for(tries = 0; tries < 4; tries++)			if(floppyrecal(dp) >= 0)				break;	dp->lasttouched = m->ticks;	fl.selected = dp;	if(dp->confused)		return -1;	return 0;}/* *  stop the floppy if it hasn't been used in 5 seconds */static voidfloppyoff(FDrive *dp){	fl.motor &= ~MOTORBIT(dp->dev);	outb(Pdor, fl.motor | Fintena | Fena | dp->dev);}/* *  send a command to the floppy */static intfloppycmd(void){	int i;	int tries;	fl.nstat = 0;	for(i = 0; i < fl.ncmd; i++){		for(tries = 0; ; tries++){			if((inb(Pmsr)&(Ffrom|Fready)) == Fready)				break;			if(tries > 1000){				DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i);				fldump();				/* empty fifo, might have been a bad command */				floppyresult();				return -1;			}			microdelay(1);		}		outb(Pfdata, fl.cmd[i]);	}	return 0;}/* *  get a command result from the floppy * *  when the controller goes ready waiting for a command *  (instead of sending results), we're done *  */static intfloppyresult(void){	int i, s;	int tries;	/* get the result of the operation */	for(i = 0; i < sizeof(fl.stat); i++){		/* wait for status byte */		for(tries = 0; ; tries++){			s = inb(Pmsr)&(Ffrom|Fready);			if(s == Fready){				fl.nstat = i;				return fl.nstat;			}			if(s == (Ffrom|Fready))				break;			if(tries > 1000){				DPRINT("floppyresult: %d stats\n", i);				fldump();				fl.confused = 1;				return -1;			}			microdelay(1);		}		fl.stat[i] = inb(Pfdata);	}	fl.nstat = sizeof(fl.stat);	return fl.nstat;}/* *  calculate physical address of a logical byte offset into the disk * *  truncate dp->length if it crosses a track boundary */static voidfloppypos(FDrive *dp, long off){	int lsec;	int ltrack;	int end;	lsec = off/dp->t->bytes;	ltrack = lsec/dp->t->sectors;	dp->tcyl = ltrack/dp->t->heads;	dp->tsec = (lsec % dp->t->sectors) + 1;	dp->thead = (lsec/dp->t->sectors) % dp->t->heads;	/*	 *  can't read across track boundaries.	 *  if so, decrement the bytes to be read.	 */	end = (ltrack+1)*dp->t->sectors*dp->t->bytes;	if(off+dp->len > end)		dp->len = end - off;}/* *  get the interrupt cause from the floppy. */static intfloppysense(void){	fl.ncmd = 0;	fl.cmd[fl.ncmd++] = Fsense;	if(floppycmd() < 0)		return -1;	if(floppyresult() < 2){		DPRINT("can't read sense response\n");		fldump();		fl.confused = 1;		return -1;	}	return 0;}static intcmddone(void *a){	USED(a);	return fl.ncmd == 0;}/* *  Wait for a floppy interrupt.  If none occurs in 5 seconds, we *  may have missed one.  This only happens on some portables which *  do power management behind our backs.  Call the interrupt *  routine to try to clear any conditions. */static voidfloppywait(int slow){	timedsleep(cmddone, 0, slow ? 5000 : 1000);	if(!cmddone(0)){		floppyintr(0);		fl.confused = 1;	}}/* *  we've lost the floppy position, go to cylinder 0. */static intfloppyrecal(FDrive *dp){	dp->ccyl = -1;	dp->cyl = -1;	fl.ncmd = 0;	fl.cmd[fl.ncmd++] = Frecal;	fl.cmd[fl.ncmd++] = dp->dev;	if(floppycmd() < 0)		return -1;	floppywait(1);	if(fl.nstat < 2){		DPRINT("recalibrate: confused %ux\n", inb(Pmsr));		fl.confused = 1;		return -1;	}	if((fl.stat[0] & (Codemask|Seekend)) != Seekend){		DPRINT("recalibrate: failed\n");		dp->confused = 1;		return -1;	}	dp->cyl = fl.stat[1];	if(dp->cyl != 0){		DPRINT("recalibrate: wrong cylinder %d\n", dp->cyl);		dp->cyl = -1;		dp->confused = 1;		return -1;	}	dp->confused = 0;	return 0;}/* *  if the controller or a specific drive is in a confused state, *  reset it and get back to a kown state */static voidfloppyrevive(void){	FDrive *dp;	/*	 *  reset the controller if it's confused	 */	if(fl.confused){		DPRINT("floppyrevive in\n");		fldump();		/* reset controller and turn all motors off */		splhi();		fl.ncmd = 1;		fl.cmd[0] = 0;		outb(Pdor, 0);		delay(10);		outb(Pdor, Fintena|Fena);		delay(10);		spllo();		fl.motor = 0;		fl.confused = 0;		floppywait(0);		/* mark all drives in an unknown state */		for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++)			dp->confused = 1;		/* set rate to a known value */		outb(Pdsr, 0);		fl.rate = 0;		DPRINT("floppyrevive out\n");		fldump();	}}/* *  seek to the target cylinder * *	interrupt, no results */static vlongpcfloppyseek(FDrive *dp, vlong off){	floppypos(dp, off);	if(dp->cyl == dp->tcyl){		dp->offset = off;		return off;	}	dp->cyl = -1;	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)		return -1;	floppywait(1);	if(fl.nstat < 2){		DPRINT("seek: confused\n");		fl.confused = 1;		return -1;	}	if((fl.stat[0] & (Codemask|Seekend)) != Seekend){		DPRINT("seek: failed\n");		dp->confused = 1;		return -1;	}	dp->cyl = dp->tcyl;	dp->offset = off;	DPRINT("seek to %d succeeded\n", dp->offset);	return dp->offset;}/* *  read or write to floppy.  try up to three times. */static longfloppyxfer(FDrive *dp, int cmd, void *a, long off, long n){	long offset;	int tries;	if(off >= dp->t->cap)		return 0;	if(off + n > dp->t->cap)		n = dp->t->cap - off;	/* retry on error (until it gets ridiculous) */	for(tries = 0; tries < dp->maxtries; tries++){		dp->len = n;		if(pcfloppyseek(dp, off) < 0){			DPRINT("xfer: seek failed\n");			dp->confused = 1;			continue;		}		/*		 *  set up the dma (dp->len may be trimmed)		 */		dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread);		if(dp->len < 0){	buggery:			dmaend(DMAchan);			continue;		}			/*		 *  start operation		 */		fl.ncmd = 0;		fl.cmd[fl.ncmd++] = cmd | (dp->t->heads > 1 ? Fmulti : 0);		fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;		fl.cmd[fl.ncmd++] = dp->tcyl;		fl.cmd[fl.ncmd++] = dp->thead;		fl.cmd[fl.ncmd++] = dp->tsec;		fl.cmd[fl.ncmd++] = dp->t->bcode;		fl.cmd[fl.ncmd++] = dp->t->sectors;		fl.cmd[fl.ncmd++] = dp->t->gpl;		fl.cmd[fl.ncmd++] = 0xFF;		if(floppycmd() < 0)			goto buggery;		/*		 *  give bus to DMA, floppyintr() will read result		 */		floppywait(0);		dmaend(DMAchan);		/*		 *  check for errors		 */		if(fl.nstat < 7){			DPRINT("xfer: confused\n");			fl.confused = 1;			continue;		}		if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){			DPRINT("xfer: failed %ux %ux %ux\n", fl.stat[0],				fl.stat[1], fl.stat[2]);			DPRINT("offset %lud len %ld\n", off, dp->len);			if((fl.stat[0]&Codemask)==Cmdexec && fl.stat[1]==Overrun){				DPRINT("DMA overrun: retry\n");			} else				dp->confused = 1;			continue;		}		/*		 *  check for correct cylinder		 */		offset = fl.stat[3] * dp->t->heads + fl.stat[4];		offset = offset*dp->t->sectors + fl.stat[5] - 1;		offset = offset * c2b[fl.stat[6]];		if(offset != off+dp->len){			DPRINT("xfer: ends on wrong cyl\n");			dp->confused = 1;			continue;		}			dp->lasttouched = m->ticks;		dp->maxtries = 20;		return dp->len;	}	return -1;}/*voidfloppymemwrite(void){	int i;	int n;	uchar *a;	FDrive *dp;	dp = &fl.d[0];	a = (uchar*)0x80000000;	n = 0;	while(n < 1440*1024){		i = floppyxfer(dp, Fwrite, a+n, n, 1440*1024-n);		if(i <= 0)			break;		n += i;	}	print("floppymemwrite wrote %d bytes\n", n);splhi(); for(;;);}*/static voidfloppyintr(Ureg *ur){	USED(ur);	switch(fl.cmd[0]&~Fmulti){	case Fread:	case Fwrite:	case Fformat:	case Fdumpreg: 		floppyresult();		break;	case Fseek:	case Frecal:	default:		floppysense();	/* to clear interrupt */		break;	}	fl.ncmd = 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -