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

📄 ar.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	struct ardevice *araddr	= sc->sc_addr;	if (!sc->sc_opened)		return (-1);	sc->sc_state = ar_cmds[cmd];	for (;;) {		if (araddr->arexc) {			/*			 * This interrupt is from the true level of arexc.			 *			 * An error has occurred.  Deal with it somehow.			 * If we are reading status, just do it; else do our own			 * RDST to find out the problem, and cancel the current			 * operation.			 */			if (sc->sc_state == RDSTinit)				goto doit;	Dprintf("ar*intr arexc set, old state %x\n", sc->sc_state);			sc->sc_oldstate = sc->sc_state;			sc->sc_state = RDSTinit;			/*			 * Clear EdgeReady and enable it so the next arrdy			 * edge will be caught (possibly inside armachine()).			 */			araddr->arcatch = 0;			araddr->arcatch = 1;			while (!armachine(sc)) {				/* Shouldn't happen! */				printf("ar*intr RDST did not return 1\n");			}			if (!sc->sc_status.FileMark) {				printf("ar: error %x\n",					*(u_short *)&sc->sc_status);				return (1);			}			/* Eof signaled now means that NEXT block is an EOF. */			sc->sc_eoflag = 1;			return (0);		}		if (araddr->arrdy) {	doit:			araddr->arcatch = 0;			araddr->arcatch = 1;			if (armachine(sc))				return (0);		}	}}/* * State machine for archive tape drive controller. * This actually accomplishes things w.r.t. the tape drive. * Returns 0 if operation still in progress, 1 if finished. * Note that we may take further interrupts after claiming that an * operation is "finished".  For example, we say a write is done when * we have transferred the last byte of the block; but there will be * an interrupt 5.5ms later to tell us it's ok to send the next block. * Eventually, we will rewind the tape asynchronously after the file is * closed, letting the user go free while it spins.  FIXME: THIS CANNOT * BE DONE until we clean up the high level code so it doesn't clobber * our variables as it is setting up to call arstart_cmd(). */armachine(sc)	register struct ar_softc *sc;{	register struct ardevice *araddr = sc->sc_addr;	register int count, i, x;	register char *byteptr;Dprintf("ar*machine(%x, %x) state %x\n", sc, araddr, sc->sc_state);	switch (sc->sc_state) {	case CMDOKinit:		/*		 * If we got here the command state is ok,		 * i.e., not in the middle of a read or write.		 */		sc->sc_state = IDLEstate;		sc->sc_cmdok = 1;		return (1);	case CLOSEinit:		/* FIXME, this is time dependent and not documented in		   the Archive manual */		araddr->aronline = 0;		/* Drop online; we're done. */		if (araddr->arrdy)			goto IdleState;	/* No interrupt will occur. */		else			goto FinState;	/* Rewinding; wait for interrupt. */#ifdef FIXME	case CLOSEend:		/* This is entered from READidle or WRidle. */		araddr->aronline = 0;		/* Drop it, causing rewind. */		goto FinState;		/* Interrupt will signal end of rew. */#endif	case WFMinit:		sc->sc_status.BOT = 0;		araddr->ardata = ARCMD_WREOF;		araddr->arreq = 1;		goto CmdState;	case RFMinit:		araddr->ardata = ARCMD_RDEOF;		araddr->arreq = 1;		goto CmdState;	case REWinit:		araddr->ardata = ARCMD_REWIND;		araddr->arreq = 1;		goto CmdState;	case TENSEinit:		araddr->ardata = ARCMD_TENSION;		araddr->arreq = 1;		goto CmdState;	case ERASEinit:		araddr->ardata = ARCMD_ERASE;		araddr->arreq = 1;		goto CmdState;	case SELinit:		araddr->ardata = ARCMD_LED | (1 << sc->sc_drive);		araddr->arreq = 1;		goto CmdState;	case DESELinit:		araddr->ardata = 1 << sc->sc_drive;		araddr->arreq = 1;		goto CmdState;	RDSTagain:		printf("ar: RDST gave Exception, retrying\n");		/* Fall thru... */	case RDSTinit:		byteptr = (char *) &sc->sc_status;		/* We could have either arrdy or arexc; remember which */		count = 0;		if (araddr->arrdy)			count = 1;		araddr->ardata = ARCMD_RDSTAT;		araddr->arreq = 1;		/*		 * Now wait for arrdy indicating command accepted.		 * Check for Exception, if we started with arrdy.  		 * (It's not legal to do RDST all the time(!).)		 */		while (!araddr->arrdy)			if (count && araddr->arexc)				goto RDSTagain;		/* Negate arreq, wait for arrdy to drop. */		araddr->arcatch = 0;	/* Clear arrdyedge */		araddr->arcatch = 1;	/* Catch edge */		araddr->arreq = 0;		/* Now xfer a byte or six. */		do {			/* Wait for edge of arrdy */			while (!araddr->arrdyedge)				if (araddr->arexc)					goto RDSTagain;			*byteptr++ = araddr->ardata;			araddr->arcatch = 0;	/* Clear edge indicator */			araddr->arcatch = 1;	/* Catch next one */			araddr->arreq = 1;	/* Tell controller we have it */			/* Ready will fall within 250ns of our arreq, but			   we're supposed to keep it high for 20us */			DELAY(30);	/* at least 20 usec */			araddr->arreq = 0;		} while (byteptr <			(char *)(&sc->sc_status) + sizeof (sc->sc_status));		/*		 * On exit from this loop, arcatch has been negated and		 * asserted, so it will correctly reflect the leading edge		 * of arrdy for the next command.		 */		sc->sc_oldstate = sc->sc_state;		sc->sc_state = FINstate;	/* Awaiting final interrupt *//* Dump status bytes after a command AR_STATUS */Dprintf("ar*RDST %x %d %d\n", *(unsigned short*)&sc->sc_status,	sc->sc_status.SoftErrs, sc->sc_status.TapeStops);/* This code is obsolete since sc_qidle, and should be replaceable   by a simple branch to RdWrFin.  However, that doesn't work, so   try this.  JCGnu, 23Nov82 */		while (!araddr->arrdy)			if (araddr->arexc)				goto RDSTagain;/* We leave the edge of Ready caught in EdgeReady, but IdleState will   disable interrupts on it. */		goto IdleState;	case READcmd:	case WRcmd:		araddr->arreq = 0;		goto next;	case READinit:		araddr->ardata = ARCMD_RDDATA;		araddr->arreq = 1;		goto next;	case READburst:		/* Read a block of data from the tape drive. */Dprintf("ar*READ addr %x count %x\n", sc->sc_bufptr, sc->sc_size);		sc->sc_status.BOT = 0;		while (!araddr->arrdy) {			if (araddr->arexc)				return (0);    /* Not yet done */			Dprintf("ar*Read no READY\n");		}		araddr->arburst = 1;			/* Begin block xfer */		count = min(sc->sc_size, AR_BSIZE);		byteptr = sc->sc_bufptr;		for (i=0; i<count; i++)			*byteptr++ = araddr->ardata; /* read data */		for (; i<AR_BSIZE; i++)			x = araddr->ardata;	/* read junk */#ifdef lint		x = x;			/* use it */#endif		araddr->arburst = 0;		sc->sc_oldstate = sc->sc_state;		sc->sc_state = READfin;		/* Like FINstate sorta */		break;	case WRinit:		araddr->ardata = ARCMD_WRDATA;		araddr->arreq = 1;		goto next;	case WRburst:		/* Write a block of data to the tape drive. */Dprintf("ar*WRITE addr %x count %x\n", sc->sc_bufptr, sc->sc_size);		while (!araddr->arrdy) {			if (araddr->arexc)				return (0);		/* Not done yet */			Dprintf("ar*Write no READY\n");		}		araddr->arburst = 1;			/* Begin block xfer */		count = AR_BSIZE;		byteptr = sc->sc_bufptr;		while (count--)			araddr->ardata = *byteptr++;		araddr->arburst = 0;		sc->sc_oldstate = sc->sc_state;		sc->sc_state = WRfin;		/* Like FINstate sorta */Dprintf("ar*machine exiting done in state %x\n", sc->sc_state);		/*		 * This code is a copy of the code at the end of this		 * switch statement, except that it returns 1 (operation		 * completed) instead of 0 (more needs doing)		 */		araddr->arrdyie = 1;		araddr->arexcie = 1;		return (1);	case CMDstate:		/* All commands that stop interacting once you say "do it" */		araddr->arreq = 0;	/* Done with command */		goto FinState;		/* Final interaction for this cmd */	IdleState:		/* Drive is idle; set IDLEstate and disable */		sc->sc_oldstate = sc->sc_state;		sc->sc_state = IDLEstate;		goto DisAble;	case WRfin:		/* Entry after writing a block */	case READfin:		/* Entry after reading a block */	case FINstate:		/* Entry after any other command */		/*		 * Go to next sequential state - WRidle, READidle, IDLEstate.		 * Disable interrupts, and return.  arstart_cmd() will later		 * put us into READ/WRburst or some commandinit state.		 */		sc->sc_oldstate = sc->sc_state;		sc->sc_state = (enum ARstates)(1 +(int)sc->sc_state);DisAble:Dprintf("ar*machine idling\n");		araddr->arrdyie = 0;		/* Negate arrdy interrupt */		return (1);			/* Tell caller op is done */	case WRidle:		/* Writing blocks, but none to write now */	case READidle:		/* Reading blocks, but don't need one now */	case IDLEstate:		/* Issuing commands, but don't have one now */		/* This can only happen if software triggers us. */		printf("ar: triggerred at idle %x\n", sc->sc_state);		goto DisAble;	/* Turn off interrupt enable again */	default:		printf("ar: invalid state %d\n", sc->sc_state);		goto FinState;		/* Is this reasonable? */	next:		/* Go to next sequential state */		sc->sc_oldstate = sc->sc_state;		sc->sc_state = (enum ARstates)(1 +(int)sc->sc_state);		break;	FinState:		sc->sc_oldstate = sc->sc_state;		sc->sc_state = FINstate;		break;	CmdState:		sc->sc_oldstate = sc->sc_state;		sc->sc_state = CMDstate;		break;	}Dprintf("ar*machine exiting in state %x\n", sc->sc_state);	/* Go to next state on the next leading edge of arrdy. */	araddr->arrdyie = 1;	/* Interrupt on arrdy leading edge */	araddr->arexcie = 1;	/* Interrupt on arexc too *//* FIXME.  Figure out where to set and unset, leave alone otherwise. */	return (0);}

⌨️ 快捷键说明

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