|
|
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);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.