File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / sys / bsc / bsc.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:24:19 2019 UTC (7 years ago) by root
Branches: bsd, MAIN
CVS tags: v12b, v121, HEAD
Power 6/32 Unix version 1.2b

/*	D.L.Buck and Associates, Inc. - 9/4/84
 *
 *	COPYRIGHT NOTICE:
 *		Copyright c 9/4/84 - An unpublished work by 
 *		D.L.Buck and Associates, Inc.
 *
 *	PROPRIETARY RIGHTS NOTICE:
 *		All rights reserved. This document and program contains
 *		proprietary information of D.L.Buck and Associates,Inc.
 *		of San Jose, California, U.S.A., embodying confidential
 *		information,  ideas, and expressions,  no part of which
 *		may be reproduced, or transmitted in any form or by any
 *		means,  electronic,  mechanical,  or otherwise, without
 *		the written permission of D.L.Buck and Associates, Inc.
 *
 * NAME
 *	bsc - bisync device driver
 *
 * DESCRIPTION
 *	This file contains the Unix system interface routines, prepared for
 *	UNIX Version 7, System III, System V, or BSD 4.2.
 *	The entry points are bscopen, bscclose, bscread, bscwrite, and
 *	bscioctl.  These routines are meant to be hardware-independent.
 */

#ifndef lint
static char bsc_c[] = "@(#)bsc.c	1.15 REL";
#endif

#include "../bsc/local.h"
#include "../bsc/bscio.h"
#include "../bsc/bsc.h"

#if defined v7 || defined BSD42
#define	delay(x)	sleep((caddr_t)&lbolt, BSCPRI)
extern int lbolt;
#endif

#if defined BSD42
#define ERRRET(x)	return x
#define	UCOUNT	uio->uio_resid
#else
#define	ERRRET(x)	u.u_error = x; return
#define	UCOUNT	u.u_count
#endif

struct bsc bsc[NVBSC*4];		/* device-specific information */
extern struct state states[];		/* state table in bscpsm.c */

/*
 *	bscopen -- prepare for BISYNC communications
 *		0) check and lock device
 *		1) set up defaults for IOCTL-provided parameters
 *		2) set up counters and fields returned via IOCTL
 *		3) set up everything else related to bsc driver
 *		4) do hardware-specific programming and checking
 *		5) wait for DSR from modem
 */
/*VARARGS1*/
bscopen (dev)				/* prepare for BISYNC communication */
register dev_t dev;
{
	register struct bsc *bp;	/* ptr to dev's bsc entry */
	int errcode;

	/* 0. Check and lock device. */
	dev = minor(dev);
/*	if (dev >= NBSC) {     */
  	if (dev >= MX_NBSC) {       
		ERRRET(ENXIO);		/* No such device		*/
	}
	bp = &bsc[dev];
	if (bp->b_lock) {		/* Is port locked?		*/
		ERRRET(EBUSY);		/* Error - port busy		*/
	}
	bp->b_lock = SSLOCK;		/* Special single station lock	*/

	/* 1. Set up defaults for ioctl-provided params			*/
	bp->b_iocin.b_blks = BSCMBLK;	/* Max block size		*/
	bp->b_hlflgs = BSCPRIM; 	/* Flags: we are primary	*/
	bp->b_iocin.b_termid[0] = '\0'; /* No terminal id		*/
	bp->b_iocin.b_hostid[0] = '\0'; /* No host id			*/
	bp->b_iocin.b_nbid =		/* Max # bids			*/
	bp->b_iocin.b_nnak =		/* Max # naks we will give	*/
	bp->b_iocin.b_nretry = 15;	/* Max # receive t/o's and naks	*/
					/*       we will accept */
	bp->b_iocin.b_nttd =		/* Max # ttds we will accept	*/
	bp->b_iocin.b_nwack = 100;	/* Max # wacks we will accept	*/
	bp->b_iocin.b_nor = 30; 	/* Max seconds to wait on initial rd */

	/* 2. Set up counters and fields returned via ioctl		*/
	bp->b_iocout.b_blks = 0;	/* # blocks sent/received */
	bp->b_iocout.b_flags = 0;	/* Flags: see definition	*/
	bp->b_iocout.b_termid[0] = '\0';/* No terminal id		*/
	bp->b_iocout.b_hostid[0] = '\0';/* No host id			*/
	bp->b_iocout.b_nbid = 0;	/* No bids so far		*/
	bp->b_iocout.b_nnak = 0;	/* No naks so far		*/
	bp->b_iocout.b_nretry = 0;	/* No retry so far		*/
	bp->b_iocout.b_nttd = 0;	/* No ttds so far		*/
	bp->b_iocout.b_nwack = 0;	/* No wacks so far		*/
	bp->b_iocout.b_nor = 0; 	/* No overruns so far		*/

	/* 3. Set up miscellaneous fields for driver			*/
	bp->b_state = 0;		/* Set initial psm state	*/
	bp->b_mode = BSC_INIT;		/* Initial mode indicates	*/
					/* haven't done any i/o yet	*/
	bp->b_rxst0 = 0;		/* Reset l/l driver state	*/
	bp->b_tmperr = 0;		/* No temp. errors yet		*/
	bp->b_sema = BSC_DDONE; 	/* Neither psm nor		*/
					/* driver busy - both done	*/

	/* 4. Initialize I/O port */
	if (errcode = bsclopn(dev, bp)) {/* device-specific open	*/
		bp->b_lock = 0;
		ERRRET(errcode);
	}

	/* 5. wait till DSR shows */
	while (bsckdsr(dev,bp), !(bp->b_hlflgs & BSC_DSR) && !u.u_error)
		delay(PSMTICK);
	if (bp->b_trace)
		wakeup(&bp->b_trace);
	if (u.u_error) {
		bp->b_lock = 0;
		bsclcls(dev, bp);
	}
#if defined BSD42
	return 0;
#endif
}

/*
 *	bscclose -- 1) send disconnect message, if we're up and running
 *		    2) turn off DTR, RTS and disable the channel
 */
bscclose(dev)
register dev_t dev;
{
	register struct bsc *bp;

	dev = minor(dev);
	bp = &bsc[dev];

/*debug*/printf("bscclose");
	/* 1. Terminate PSM processing, kill receive and tracing */
	if ( (bp->b_hlflgs & (BSCMPT|BSC_DSR)) != BSC_DSR ||
		bp->b_mode == BSC_INIT)
		bp->b_mode = BSC_CLOSED;	/* Leave quietly */
	else	{				/* Point-to-point ... */
		bp->b_mode = BSC_CL1;		/* Send Disconnect */
		while (bp->b_mode != BSC_CLOSED &&
		       (bp->b_hlflgs & BSC_DSR))	/* Wait */
			delay(PSMTICK);
	}
	bp->b_rclptr = (char *)0;		/* terminate receive */
	bstclose(dev);				/* terminate tracing */

	/* 2. Unlock the port */
/*debug*/printf("close:unlock");
	bp->b_lock = 0;

	/* 3. Turn off DTR */
	bsclcls (dev, bp);
#if defined BSD42
	return 0;
#endif
}

/*
 *	bscread -- read next data block.
 *		0) If error latch set or no DSR, EIO!
 *		1) if mode = write, EINVAL!
 *		2) if mode = init, initialize bsc, mode <- idle
 *		3) if mode = idle, sync with psm, set b_nor timeout,
 *		   mode <- read
 *		4) while buffer empty and no errs and not eof, sleep
 *		5) Check termination condition:
 *		   a) If err, set mode<-idle, reset hlflgs, set EIO error.
 *		   b) If signal caused termination, force rxto & reread.
 *		   c) If EOF, set mode<-IDLE, reset hlflgs and sema, return.
 *		   d) Otherwise, full buffer.
 *		      If size not zero, copy it out and mark it empty.
 */
#if defined BSD42
bscread(dev,uio)
register dev_t dev;
struct uio *uio;
#else
bscread(dev)
register dev_t dev;
#endif
{
	register struct bsc *bp;	/* ptr to bsc device info.	*/
	register int l;			/* length info.			*/
	int x;				/* prty save area		*/
	int errcode = 0;		/* Error code upon exit		*/

	dev = minor(dev);
	bp = &bsc[dev];

	/* 0. Check error latch and DSR					*/
	if (!(bp->b_hlflgs & BSC_DSR) ||	/* No DSR!		*/
	    (bp->b_hlflgs & BSC_ERR)) {		/* Error logged		*/
		if (!(bp->b_hlflgs & BSC_ERR)) {/* Ensure latched err	*/
			bp->b_hlflgs |= BSC_ERR;
			bp->b_iocout.b_flags = BSCNDSR;
		}
		bp->b_mode = BSC_IDLE;
		ERRRET(EIO);
	}

	switch (bp->b_mode) {
	case BSC_WRITE:				/* Error!		*/
		ERRRET(EINVAL);

	case BSC_INIT:			/* First read or write action	*/
		bscsetup(dev);		/* Start by initializing	*/
		bp->b_mode = BSC_IDLE;

	case BSC_IDLE:			/* Moving from Idle to Write	*/
		while (!(bp->b_sema & BSC_PDONE) &&
			!(bp->b_hlflgs & BSC_ERR))
			delay(PSMTICK);	/* Synchronize			*/
		if (bp->b_hlflgs & BSC_ERR) {
			bp->b_mode = BSC_IDLE;
			ERRRET(EIO);
		}
		/* Set Read Timeout in Ticks				*/
		bp->b_rdflag = bp->b_iocin.b_nor*PSMTPS;
		bp->b_mode = BSC_READ;	/* Now we're in read state	*/
		x = spl8();		/* *** protect flags ***	*/
		bp->b_sema |= BSC_DBUSY;/* Driver now busy		*/
		bp->b_sema &= ~BSC_DDONE;
		splx(x);		/* End protection		*/

	case BSC_READ:			/* Not first read		*/
forceread:
		x = spl8();
		/* Test for no-delay mode and not ready			*/
		if (bp->b_sema & BSC_SEENBUF) {
			bp->b_hlflgs &= ~BSC_FULL;
			bp->b_sema &= ~BSC_SEENBUF;
			if (states[bp->b_state].s_type == 'd' &&
			    bp->b_alenb) {	/* Decision wait?	*/
				bp->b_alenb = 0;/* Disable pto		*/
				splx(x);
				bscpsm(dev);	/* Wake up PTO		*/
			}
		}
		if ((bp->b_sema & BSC_NDLY) &&
		    !(bp->b_hlflgs & (BSC_FULL|BSC_ERR|BSC_XLAST))) {
			splx(x);
			ERRRET(EAGAIN);		/* NO DELAY		*/
		}
		while (!(bp->b_hlflgs & (BSC_FULL|BSC_ERR|BSC_XLAST)))
			sleep (bp->b_buffer, BSCPRI);	/* Take a nap	*/
		splx(x);

		bp->b_rdflag = 0;		/* Cancel read timeout	*/

		if (bp->b_hlflgs & BSC_XLAST) {
			x = spl8();		/* Protect flags	*/
			bp->b_mode = BSC_IDLE;
			bp->b_hlflgs &= ~(BSC_XLAST|BSC_XTRN);
			bp->b_sema |= BSC_DDONE;
			bp->b_sema &= ~BSC_DBUSY;
			splx(x);
			goto readexit;		/* EOF!			*/
		}

		if (bp->b_hlflgs & BSC_ERR) {	/* Error way out	*/
			bp->b_hlflgs &= ~(BSC_XLAST|BSC_XTRN);
			bp->b_hlflgs &= ~BSC_FULL;
			bp->b_sema &= ~BSC_SEENBUF;
			bp->b_mode = BSC_IDLE;
			ERRRET(EIO);
		} else {		/* No errors - copy buffer out	*/
			l = bp->b_bsize;/* Size of data in buffer	*/
			if (l > UCOUNT)
				l = UCOUNT;
			if (l)	/* transfer data */
#if defined BSD42
				errcode = uiomove(bp->b_buffer,l,UIO_READ,uio);
#else
				if (iomove (bp->b_buffer, l, B_READ))
					errcode = EFAULT;
#endif
		}

		/* If FAST-ACKNOWLEDGE mode in effect, ACK on next read	*/
		if (bp->b_sema & BSC_FACK) {
			bp->b_sema |= BSC_SEENBUF;
			goto readret;
		} else
			bp->b_hlflgs &= ~BSC_FULL;	/* Mark empty	*/
readexit:	x = spl8();
		if (states[bp->b_state].s_type == 'd' &&
		    bp->b_alenb) {		/* Decision wait?	*/
			bp->b_alenb = 0;	/* Disable PTO		*/
			splx(x);
			bscpsm(dev);		/* Awaken PSM		*/
		}
		else	splx(x);
	}
readret:
#if defined BSD42
	return errcode;
#else
	if (errcode)
		u.u_error = errcode;
#endif
}

/*
 *	bscwrite -- 0) if no DSR or error latch set, EIO
 *		    1) if length to write zero or > max, EINVAL
 *		    2) if mode = read, EINVAL!
 *		    3) if mode = init, prime the driver
 *		    4) if mode = idle, init, or write,
 *			  a) set mode to write,
 *			  b) wait till buffer empty,
 *			  c) fill the buffer, 
 *			  d) set flag to show buffer full.
 */
#if defined BSD42
bscwrite(dev,uio)
register dev_t dev;
struct uio *uio;
#else
bscwrite(dev)
register dev_t dev;
#endif
{
	register int l;			/* length given us		*/
	register struct bsc *bp;	/* ptr to bsc dev info		*/
	int x;				/* priority save area		*/
	int errcode = 0;		/* Error code to be returned	*/

	bp = &bsc[dev = minor(dev)];

	/* 0. Check error latch and DSR */
	if (bp->b_hlflgs & BSC_ERR && bp->b_iocout.b_flags == BSCRXTO) {
		bp->b_hlflgs &= ~BSC_ERR;
		bp->b_iocout.b_flags = 0;
		bp->b_mode = BSC_IDLE;
	}
	if (!(bp->b_hlflgs & BSC_DSR) || (bp->b_hlflgs & BSC_ERR)) {
		if (!(bp->b_hlflgs & BSC_ERR)) {/* ensure latched err */
			bp->b_hlflgs |= BSC_ERR;
			bp->b_iocout.b_flags = BSCNDSR;
		}
		bp->b_mode = BSC_IDLE;
		ERRRET(EIO);
	}

	/* 1. Check length and other errors */
	if ( (l = UCOUNT) == 0 || l > bp->b_iocin.b_blks) {	/* bad length */
		ERRRET(EINVAL);
	}

	/* 2. process according to mode */
	switch (bp->b_mode)
	{
	case BSC_READ:
		if ((bp->b_sema & BSC_FACK) && (bp->b_sema & BSC_SEENBUF)) {
			bp->b_hlflgs &= ~BSC_FULL;
			bp->b_sema &= ~BSC_SEENBUF;
			bp->b_mode = BSC_WRITE;
			goto casewrite;
		}
		if (bp->b_rdflag == 0) {
			ERRRET(EINVAL);	/* oops - can't read now! */
		} else 	{
			bp->b_rdflag = 1;	/* kill read timeout */
			x = spl8();		/* *** protect flags *** */
			bp->b_sema &= ~BSC_DBUSY;
			bp->b_sema |= BSC_DDONE;
			splx(x);		/* end protection */
			/* wait till timeout */
			while (bp->b_mode == BSC_READ &&
			       !(bp->b_hlflgs & BSC_ERR))
				delay(PSMTICK);
		}

	case BSC_INIT:
		bscsetup(dev);		/* set up device */
		bp->b_mode = BSC_IDLE;

	case BSC_IDLE:
		if (bp->b_hlflgs & BSC_FULL) {
			ERRRET(EINVAL);	/* caller needs to read */
		}
		while (!(bp->b_sema & BSC_PDONE) &&
		       !(bp->b_hlflgs & BSC_ERR))
			delay(PSMTICK);	/* Synchronize */
		if (bp->b_hlflgs & BSC_ERR) {
			bp->b_mode = BSC_IDLE;
			ERRRET(EIO);
		}

		bp->b_mode = BSC_WRITE;	/* set new mode */
		x = spl8();		/* *** protect flags *** */
		bp->b_hlflgs &= ~BSC_ERR;	/* reset possible err */
		bp->b_sema |= BSC_DBUSY;/* driver now busy */
		bp->b_sema &= ~BSC_DDONE;
		splx(x);		/* *** end protection *** */

casewrite:
	case BSC_WRITE:
		x = spl8();
		while ((bp->b_hlflgs & BSC_FULL) && 	/* wait til empty */
		       !(bp->b_hlflgs & BSC_ERR))	/* and no error */
			sleep (bp->b_buffer, BSCPRI);	/* take a nap */
		splx(x);

		if (bp->b_hlflgs & BSC_ERR){	/* if error, EIO */
			bp->b_hlflgs &= ~(BSC_XLAST|BSC_FULL|BSC_XTRN);
			bp->b_mode = BSC_IDLE;
			errcode = EIO;
			break;
		}
		/* copy data to buffer */
#if defined BSD42
		errcode = uiomove(bp->b_buffer, l, UIO_WRITE, uio);
#else
		if (iomove (bp->b_buffer, l, B_WRITE))
			errcode = EFAULT;
#endif
		bp->b_bsize = l;			/* save size */
		x = spl8();
		bp->b_hlflgs |= BSC_FULL;		/* bufr now full */
		if (states[bp->b_state].s_type == 'd' &&
		    bp->b_alenb) {			/* decision wait? */
			bp->b_alenb = 0;		/* disable pto */
			splx(x);
			bscpsm(dev);			/* wake 'em up */
		} else	splx(x);

		if (bp->b_hlflgs & BSC_XLAST) {	/* if last block, wait*/
			x = spl8();
			while ((bp->b_hlflgs & BSC_FULL) && /* wait til empty */
			       !(bp->b_hlflgs & BSC_ERR))   /* and no error */
				sleep (bp->b_buffer, BSCPRI);/* take a nap */
			splx(x);
			if (bp->b_hlflgs & BSC_ERR)	/* if error, EIO */
				errcode = EIO;
			else {
				x = spl8();	/* *** protect flags *** */
				bp->b_sema |= BSC_DDONE;
				bp->b_sema &= ~BSC_DBUSY;
				splx(x);	/* *** end protection *** */
			}
			bp->b_mode = BSC_IDLE;
			x = spl8();	/* *** protect flags *** */
			bp->b_hlflgs &= ~(BSC_XLAST|BSC_FULL|BSC_XTRN);
			splx(x);	/* end protection */
		}
	}
#if defined BSD42
	return errcode;
#else
	if (errcode)
		u.u_error = errcode;
#endif
}

/*	bscioctl -- set options or get counter values
 *		    Depending on cmd:
 *		    BSCGET   - copy b_iocout to user's area
 *		    BSCSET   - copy user's values to b_iocin (set stuff)
 *		    BSCTRNSP - set transparent mode flag
 *		    BSCNTRNS - reset transparent mode flag
 *		    BSCSOH   - set send SOH flag
 *		    BSCNSOH  - turn off SOH flag
 *		    BSCLAST  - set send last flag
 *		    BSCNDLY  - set NO DELAY flag
 */
/*VARARGS3*/
bscioctl(dev, cmd, arg)
register dev_t dev;
struct bscio *arg; 
{
	register struct bsc *bp;	/* ptr to dev info */
	struct bscio tmp;		/* temp struct for chk'g user params*/
	register int x;
	int y, errcode = 0;

	bp = &bsc[dev = minor(dev)];
	if (cmd != BSCGET && cmd != BSCSET) {	/* if write op, wait on buf */
		x = spl8();
		while (bp->b_mode == BSC_WRITE && bp->b_hlflgs & BSC_FULL)
			sleep (bp->b_buffer, BSCPRI);
		splx(x);
	}
	switch (cmd) {
	case BSCGET:
		x = spl8();
#if defined BSD42
		bcopy(&bp->b_iocout, arg, sizeof bp->b_iocout);
#else
		if (copyout(&bp->b_iocout, arg, sizeof bp->b_iocout))
			errcode = EFAULT;
#endif
		bp->b_iocout.b_flags = 0;
		if (bp->b_hlflgs & BSC_ERR) {	/* error latch set? */
			bp->b_hlflgs &= ~(BSC_ERR|BSC_XLAST|BSC_FULL|BSC_XTRN);
			bp->b_sema &= ~BSC_DBUSY;
			bp->b_sema |= BSC_DDONE;
		}
		splx(x);
		break;

	case BSCSET:
		if (bp->b_mode == BSC_READ || bp->b_mode == BSC_WRITE) {
			ERRRET(EINVAL);
		}
#if defined BSD42
		bcopy(arg, &tmp, sizeof tmp);
#else
		if (copyin (arg, &tmp, sizeof tmp)) {
			errcode = EFAULT;
			break;
		}
#endif
		if (tmp.b_blks > BSCMBLK) {	/* block size too big? */
			ERRRET(EINVAL);
		}
		bcopy (/*from*/&tmp, /*to*/&bp->b_iocin, sizeof tmp);
		x = spl8();		/* *** protect hlflgs */
		bp->b_hlflgs &= ~BSC_UFLAGS;	/* throw out old user flags */
		bp->b_hlflgs |= (tmp.b_flags & BSC_UFLAGS);
		splx(x);		/* *** end protection */
		bscparam(dev);			/* redo parameters */
		break;

	case BSCTRNSP:
		x = spl8();		/* *** protect hlflgs */
                bp->b_hlflgs |= BSC_XTRN; 	/* set transparent mode */
		splx(x);		/* *** end protection */
		break;

	case BSCNTRNS:
		x = spl8();		/* *** protect hlflgs */
		bp->b_hlflgs &= ~BSC_XTRN;	/* reset transp. mode */
		splx(x);		/* *** end protection */
		break;

	case BSCSOH:
		x = spl8();		/* *** protect hlflgs */
		bp->b_hlflgs |= BSC_XSOH;	/* set send SOH flag */
		splx(x);		/* *** end protection */
		break;

	case BSCNSOH:
		x = spl8();		/* *** protect hlflgs */
		bp->b_hlflgs &= ~BSC_XSOH;	/* clear send SOH flag*/
		splx(x);		/* *** end protection */
		break;

	case BSCLAST:
		x = spl8();		/* *** protect hlflgs */
		bp->b_hlflgs |= BSC_XLAST;	/* set send last blk flag */
		splx(x);		/* *** end protection */
		break;

	case BSCID:
		y = (bp->b_iocin.b_flags & BSCASCII)? 0x20 : 0x40;
#if defined BSD42
		bcopy(&y,arg,sizeof y);
#else
		copyout(&y,(int *)arg,sizeof y);
#endif
		break;

	case BSCNDLY:
		x = spl8();		/* *** protect flags */
		bp->b_sema |= BSC_NDLY;		/* Set NO DELAY flag */
		splx(x);		/* *** end protection */
		break;

	case BSCFACK:
		x = spl8();		/* *** protect flags */
		bp->b_sema |= BSC_FACK;		/* Set FAST ACKNOWLEDGE	*/
		splx(x);		/* *** end protection */
		break;

	default:
		ERRRET(EINVAL);
	}
#if defined BSD42
	return errcode;
#else
	if (errcode)
		u.u_error = errcode;
#endif
}

/*
 *	bscsetup -- start the psm (protocol state machine)
 *		1) if state > 0, already started
 *		2) invoke the psm
 *		3) set timeout for 1 tick for psm
 */
bscsetup(dev)
register dev_t dev;
{
	void bscpto();

	if (bsc[dev].b_state || bsc[dev].b_mode != BSC_INIT)
		return;
	bscpsm(dev);
	timeout (bscpto, (caddr_t)dev, PSMTICK);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.