executor/src/serial.c

1039 lines
23 KiB
C

/*
* Copyright 1989, 1990, 1995, 1997 by Abacus Research and
* Development, Inc. All rights reserved.
*/
/*
* This file is an ugly mess of UNIX specific code portable Mac-side code.
* The UNIX specific stuff should be put in its appropriate place sometime.
*/
#if !defined (OMIT_RCSID_STRINGS)
char ROMlib_rcsid_serial[] =
"$Id: serial.c 88 2005-05-25 03:59:37Z ctm $";
#endif
#include "rsys/common.h"
#if defined (MACOSX)
#warning "No serial support for now"
#else /* !defined (MACOSX) */
#include "Serial.h"
#include "DeviceMgr.h"
#include "FileMgr.h"
#include "MemoryMgr.h"
#include "OSUtil.h"
#include "rsys/file.h"
#include "rsys/hfs.h"
#include "rsys/serial.h"
#if defined (MSDOS)
#include "dosserial.h"
#endif
#if defined (CYGWIN32)
#include "win_serial.h"
#endif
#if !defined (CYGWIN32)
#include <termios.h>
#endif
#if defined (LINUX)
#include <sys/ioctl.h>
#endif
#if defined (__alpha) || defined (LINUX)
#define TERMIO
/* #define MSDOS ick! */
#endif
/*
* TODO:
*
* Post events on break action or hardware handshake changes IMII-247
* Support KillIO from the device manager IMII-248
* Hardware handshaking on machines that support it IMII-252
*
* Finish up the get status routine?
*/
#define AINNAME "\004.AIn"
#define AOUTNAME "\005.AOut"
#define BINNAME "\004.BIn"
#define BOUTNAME "\005.BOut"
#define AINREFNUM (-6)
#define AOUTREFNUM (-7)
#define BINREFNUM (-8)
#define BOUTREFNUM (-9)
#if !defined(XONC)
#define XONC '\21'
#define XOFFC '\23'
#endif
#define SER_START (1)
#define SER_STOP (0)
A1(PUBLIC, OSErr, RAMSDOpen, SPortSel, port) /* IMII-249 */
{
OSErr err;
INTEGER rn;
switch (port) {
case sPortA:
if ((err = OpenDriver((StringPtr) AINNAME, &rn)) == noErr)
err = OpenDriver((StringPtr) AOUTNAME, &rn);
break;
case sPortB:
if ((err = OpenDriver((StringPtr) BINNAME, &rn)) == noErr)
err = OpenDriver((StringPtr) BOUTNAME, &rn);
break;
default:
err = openErr;
break;
}
return err;
}
A1(PUBLIC, void, RAMSDClose, SPortSel, port) /* IMII-250 */
{
switch (port) {
case sPortA:
(void) CloseDriver(AINREFNUM);
(void) CloseDriver(AOUTREFNUM);
break;
case sPortB:
(void) CloseDriver(BINREFNUM);
(void) CloseDriver(BOUTREFNUM);
break;
}
}
#define SERSET 8 /* IMII-250 */
A2(PUBLIC, OSErr, SerReset, INTEGER, rn, INTEGER, config) /* IMII-250 */
{
config = CW (config);
return Control(rn, SERSET, (Ptr) &config);
}
#define SERSETBUF 9 /* IMII-251 */
A3(PUBLIC, OSErr, SerSetBuf, INTEGER, rn, Ptr, p, INTEGER, len) /* IMII-251 */
{
sersetbuf_t temp;
temp.p = RM (p);
temp.i = CW (len);
return Control(rn, SERSETBUF, (Ptr) &temp);
}
#define SERHSHAKE 10 /* IMII-251 */
A2(PUBLIC, OSErr, SerHShake, INTEGER, rn, SerShk, flags) /* IMII-251 */
{
return Control(rn, SERHSHAKE, (Ptr) &flags);
}
#define SERSETBRK 12 /* IMII-252 */
A1(PUBLIC, OSErr, SerSetBrk, INTEGER, rn) /* IMII-252 */
{
return Control(rn, SERSETBRK, (Ptr) 0);
}
#define SERCLRBRK 11 /* IMII-253 */
A1(PUBLIC, OSErr, SerClrBrk, INTEGER, rn) /* IMII-253 */
{
return Control(rn, SERCLRBRK, (Ptr) 0);
}
#define SERGETBUF 2 /* IMII-253 */
A2(PUBLIC, OSErr, SerGetBuf, INTEGER, rn, LONGINT *, lp) /* IMII-253 */
{
INTEGER status[11];
OSErr err;
if ((err = Status(rn, SERGETBUF, (Ptr) status)) == noErr)
*lp = *(LONGINT *)status;
return err;
}
#define SERSTATUS 8 /* IMII-253 */
A2(PUBLIC, OSErr, SerStatus, INTEGER, rn, SerStaRec *, serstap) /* IMII-253 */
{
INTEGER status[11];
OSErr err;
if ((err = Status(rn, SERSTATUS, (Ptr) status)) == noErr)
BlockMove((Ptr) status, (Ptr) serstap, (Size) sizeof(*serstap));
return err;
}
#define OPENBIT (1 << 0)
#if !defined(MSDOS) && !defined (CYGWIN32)
#if defined(TERMIO)
typedef struct {
LONGINT fd; /* will be the same for both In and Out */
struct termio state;
} hidden, *hiddenp;
#else
typedef struct {
LONGINT fd; /* will be the same for both In and Out */
struct sgttyb sgttyb;
struct tchars tchars;
ULONGINT lclmode;
} hidden, *hiddenp;
#endif
#else
typedef struct
{
LONGINT fd; /* probably need to save more state information */
/* right now we just use fd to keep track of which port we're talking to */
}
hidden, *hiddenp;
#endif
MAKE_HIDDEN(hiddenp);
typedef HIDDEN_hiddenp *hiddenh;
A1(PRIVATE, DCtlPtr, otherdctl, ParmBlkPtr, pbp)
{
DCtlHandle h;
h = 0;
switch (CW(pbp->cntrlParam.ioCRefNum)) {
case AINREFNUM:
h = GetDCtlEntry(AOUTREFNUM);
break;
case AOUTREFNUM:
h = GetDCtlEntry(AINREFNUM);
break;
case BINREFNUM:
h = GetDCtlEntry(BOUTREFNUM);
break;
case BOUTREFNUM:
h = GetDCtlEntry(BINREFNUM);
break;
}
return h ? STARH(h) : 0;
}
#if defined (LINUX) || defined (NEXTSTEP)
/*
* NOTE: Currently we're using cufa and cufb; we really should
* delay the opening until we know just what type of flow
* control the user wants to do.
*/
PRIVATE char *specialname(ParmBlkPtr pbp, const char **lockfilep,
const char **tempfilep)
{
char *retval;
switch (CW(pbp->cntrlParam.ioCRefNum)) {
case AINREFNUM:
case AOUTREFNUM:
#if defined (NEXTSTEP)
retval = "/dev/cufa";
*lockfilep = "/usr/spool/uucp/LCK/LCK..cufa";
*tempfilep = "/usr/spool/uucp/LCK/etempcufa";
#elif defined (LINUX)
retval = "/dev/cua0";
*lockfilep = 0; /* for now */
*tempfilep = 0; /* for now */
#endif
break;
case BINREFNUM:
case BOUTREFNUM:
#if defined (NEXTSTEP)
retval = "/dev/cufb";
*lockfilep = "/usr/spool/uucp/LCK/LCK..cufb";
*tempfilep = "/usr/spool/uucp/LCK/etempcufa";
#elif defined (LINUX)
retval = "/dev/cua1";
*lockfilep = 0;
*tempfilep = 0;
#endif
break;
default:
*lockfilep = 0;
retval = 0;
}
return retval;
}
#endif /* defined (LINUX) || defined (NEXTSTEP) */
typedef void (*compfuncp)( void );
#if defined(BINCOMPAT)
void callcomp(ParmBlkPtr pbp, compfuncp comp, OSErr err)
{
EM_A0 = (LONGINT) (long) US_TO_SYN68K(pbp);
EM_A1 = (LONGINT) (long) US_TO_SYN68K(comp);
EM_D0 = (unsigned short) err; /* TODO: unsigned short ? */
CALL_EMULATOR((syn68k_addr_t) (long) comp);
}
#define DOCOMPLETION(pbp, err) \
(pbp)->ioParam.ioResult = CW(err); \
if (((pbp)->ioParam.ioTrap & asyncTrpBit) && (pbp)->ioParam.ioCompletion) \
callcomp(pbp, (compfuncp) CL((long)(pbp)->ioParam.ioCompletion), err); \
return err
#else
#warning BINCOMPAT not defined
#define DOCOMPLETION(pbp, err) \
(pbp)->ioParam.ioResult = CW(err); \
if ((pbp)->ioParam.ioTrap & asyncTrpBit) \
(*(compfuncp) (pbp)->ioParam.ioCompletion)(); \
return err
#endif
#define SERIALDEBUG
#if defined (LINUX) || defined (NEXTSTEP)
PRIVATE const char *lockname;
#endif
A2(PUBLIC, OSErr, ROMlib_serialopen, ParmBlkPtr, pbp, /* INTERNAL */
DCtlPtr, dcp)
{
OSErr err;
auto DCtlPtr otherp; /* auto due to old compiler bug */
hiddenh h;
#if defined (LINUX) || defined (NEXTSTEP)
const char *devname, *tempname;
LONGINT fd, ourpid, theirpid, newfd, oumask;
#endif
err = noErr;
if (!(dcp->dCtlFlags & CWC(OPENBIT))) {
h = (hiddenh) NewHandle(sizeof(hidden));
dcp->dCtlStorage = (Handle) RM(h);
otherp = otherdctl(pbp);
if (otherp && (otherp->dCtlFlags & CWC(OPENBIT))) {
*STARH(h) = *STARH((hiddenh) (long) MR(otherp->dCtlStorage));
dcp->dCtlFlags |= CWC(OPENBIT);
} else {
#if defined (LINUX) || defined (NEXTSTEP)
err = permErr;
if ((devname = specialname(pbp, &lockname, &tempname))) {
oumask = umask(0);
if (!tempname)
err = noErr;
else if ((fd = Uopen(tempname, O_BINARY|O_CREAT|O_WRONLY, 0666L))
>= 0) {
ourpid = getpid();
if (write(fd, &ourpid, sizeof(ourpid)) == sizeof(ourpid)) {
if (Ulink(tempname, lockname) == 0)
err = noErr;
else {
if ((newfd = Uopen(lockname, O_BINARY|O_RDWR, 0))
>= 0) {
if (read(newfd, &theirpid, sizeof(theirpid))
== sizeof(theirpid))
if ((kill(theirpid, 0) != 0) &&
errno == ESRCH) {
err = noErr;
Uunlink(lockname);
Ulink(tempname, lockname);
}
close(newfd);
}
}
Uunlink(tempname);
}
close(fd);
}
umask(oumask);
}
#endif
if (err == noErr) {
#if defined (LINUX) || defined (NEXTSTEP)
HxX(h, fd) = ROMlib_priv_open(devname, O_BINARY|O_RDWR);
if (HxX(h, fd) < 0)
err = HxX(h, fd); /* error return piggybacked */
else {
#if defined(TERMIO)
err = ioctl(HxX(h, fd), TCGETA, &HxX(h, state)) < 0 ?
ROMlib_maperrno() : noErr;
#else
if (ioctl(HxX(h, fd), TIOCGETP, &HxX(h, sgttyb)) < 0 ||
ioctl(HxX(h, fd), TIOCGETC, &HxX(h, tchars)) < 0 ||
ioctl(HxX(h, fd), TIOCLGET, &HxX(h, lclmode)) < 0)
err = ROMlib_maperrno();
#endif
#else
HxX(h, fd) = (CW(pbp->cntrlParam.ioCRefNum) == AINREFNUM ||
CW(pbp->cntrlParam.ioCRefNum) == AOUTREFNUM) ? 0 : 1;
#endif
dcp->dCtlFlags |= CWC(OPENBIT);
SerReset(CW(pbp->cntrlParam.ioCRefNum),
(CW(pbp->cntrlParam.ioCRefNum) == AINREFNUM ||
CW(pbp->cntrlParam.ioCRefNum) == AOUTREFNUM) ?
CW(SPPortA) : CW(SPPortB));
#if defined (LINUX) || defined (NEXTSTEP)
}
#endif
}
}
}
#if defined(SERIALDEBUG)
warning_trace_info("serial open returning %d", (LONGINT) err);
#endif
DOCOMPLETION(pbp, err);
}
A2(PUBLIC, OSErr, ROMlib_serialprime, ParmBlkPtr, pbp, /* INTERNAL */
DCtlPtr, dcp)
{
OSErr err;
hiddenh h;
char *buf;
size_t req_count;
buf = (char *) MR (pbp->ioParam.ioBuffer);
req_count = CL (pbp->ioParam.ioReqCount);
err = noErr;
if (!(dcp->dCtlFlags & CWC(OPENBIT)))
err = notOpenErr;
else {
#if defined(SERIALDEBUG)
warning_trace_info ("serial prime code %d", (LONGINT) (CW(pbp->ioParam.ioTrap) & 0xFF));
#endif
h = (hiddenh) MR(dcp->dCtlStorage);
switch (CW(pbp->ioParam.ioTrap) & 0xFF) {
case aRdCmd:
if (CW(pbp->cntrlParam.ioCRefNum) != AINREFNUM &&
CW(pbp->cntrlParam.ioCRefNum) != BINREFNUM)
err = readErr;
else {
/* this may have to be changed since we aren't looking for
parity and framing errors */
#if defined (LINUX) || defined (NEXTSTEP)
pbp->ioParam.ioActCount = CL(read(HxX(h, fd), buf, req_count));
#elif defined (MSDOS) || defined (CYGWIN32)
pbp->ioParam.ioActCount = CL(serial_bios_read(HxX(h, fd), buf,
req_count));
#else
#warning not sure what to do here
#endif
#if defined(SERIALDEBUG)
warning_trace_info ("serial prime read %d bytes, first is 0x%0x",
(LONGINT) CL(pbp->ioParam.ioActCount),
(LONGINT) (unsigned char) buf[0]);
#endif
}
break;
case aWrCmd:
if (CW(pbp->cntrlParam.ioCRefNum) != AOUTREFNUM &&
CW(pbp->cntrlParam.ioCRefNum) != BOUTREFNUM)
err = writErr;
else {
#if defined(SERIALDEBUG)
warning_trace_info ("serial prime writing %d bytes, first is 0x%0x",
(LONGINT) req_count,
(LONGINT) (unsigned char) buf[0]);
#endif
#if defined (LINUX) || defined (NEXTSTEP)
pbp->ioParam.ioActCount = CL(write(HxX(h, fd),
buf, req_count));
#elif defined (MSDOS) || defined (CYGWIN32)
pbp->ioParam.ioActCount = CL( serial_bios_write(HxX(h, fd),
buf, req_count));
#else
#warning not sure what to do here
#endif
}
break;
default:
err = badUnitErr;
break;
}
}
#if defined(SERIALDEBUG)
warning_trace_info ("serial prime returning %d", (LONGINT) err);
#endif
DOCOMPLETION(pbp, err);
}
#if defined(TERMIO)
#define OURCS7 (CS7)
#define OURCS8 (CS8)
#define OURODDP (PARENB|PARODD)
#define OUREVENP (PARENB)
#else
#define OURCS7 (0)
#if defined(NEXTSTEP)
#define OURCS8 (LPASS8|LPASS8OUT)
#else
#define OURCS8 (LPASS8)
#endif
#define OURODDP (ODDP)
#define OUREVENP (EVENP)
#endif
A2(PRIVATE, OSErr, serset, LONGINT, fd, INTEGER, param)
{
#if defined (MSDOS) || defined (CYGWIN32)
OSErr retval;
retval = serial_bios_serset (fd, param);
return retval;
#else
#if defined(TERMIO)
struct termio settings;
#else
struct sgttyb sgttyb;
struct tchars tchars;
ULONGINT lclmode;
#endif
OSErr err;
LONGINT baud, csize, stopbits, parity;
#if !defined (LETGCCWAIL)
baud = 0;
csize = 0;
stopbits = 0;
#endif
err = noErr;
switch (param & 0x3FF) {
case baud300:
baud = B300;
break;
case baud600:
baud = B600;
break;
case baud1200:
baud = B1200;
break;
case baud1800:
baud = B1800;
break;
case baud2400:
baud = B2400;
break;
case baud4800:
baud = B4800;
break;
case baud9600:
baud = B9600;
break;
case baud19200:
baud = EXTA;
break;
case 1: /* really 38400 according to Terminal 2.2 source */
baud = EXTB;
break;
case baud3600: /* these case labels aren't necessary since they */
case baud7200: /* fall into default anyway, just thought you */
case baud57600: /* might like to know what you're missing */
default:
/*
* NOTE: setting controlErr here isn't probably a good idea, since
* Compuserve Signup does a serset with baud57600 and then later
* adjusts the baud with a "setbaud"
*/
#if 0
err = controlErr;
#else
baud = B2400;
#endif
break;
}
switch (param & 0xC00) {
case data5:
case data6:
err = controlErr;
break;
case data7:
csize = OURCS7;
break;
case data8:
csize = OURCS8;
break;
}
switch (param & 0x3000) {
case oddParity:
parity = OURODDP;
break;
case evenParity:
parity = OUREVENP;
break;
default:
parity = 0;
break;
}
switch ((param >> 14) & 0x3) {
case 1:
stopbits = 0;
break;
case 3:
#if defined(TERMIO)
stopbits = CSTOPB;
break;
#endif
case 0:
case 2:
err = controlErr;
break;
}
if (err == noErr) {
#if defined(TERMIO)
settings.c_iflag = IGNPAR | IXON | IXOFF;
settings.c_oflag = 0;
settings.c_cflag = baud | csize | stopbits | parity;
settings.c_lflag = 0;
settings.c_line = 0; /* TODO: find out real value here */
err = ioctl(fd, TCSETAW, &settings) < 0 ? ROMlib_maperrno() : noErr;
#else
sgttyb.sg_ispeed = sgttyb.sg_ospeed = baud;
sgttyb.sg_erase = -1;
sgttyb.sg_kill = -1;
sgttyb.sg_flags = TANDEM | CBREAK | parity;
tchars.t_intrc = -1;
tchars.t_quitc = -1;
#if 0 /* This isn't the place to mess with flow control */
if (sershkp->fXOn || sershkp->fInX) {
tchars.t_startc = sershkp->xOn;
tchars.t_stopc = sershkp->xOff;
} else {
tchars.t_startc = sershkp->xOn;
tchars.t_stopc = sershkp->xOff;
}
/* Cliff, LDECCTQ restricts XON to startc ONLY! --Lee */
lclmode = sershkp->fXOn ? LDECCTQ : 0;
#else
lclmode = 0;
#endif
tchars.t_eofc = -1;
tchars.t_brkc = -1;
lclmode |= LLITOUT | LNOHANG | csize | LNOFLSH;
if (ioctl(fd, TIOCSETP, &sgttyb) < 0 ||
ioctl(fd, TIOCSETC, &tchars) < 0 ||
ioctl(fd, TIOCLSET, &lclmode) < 0)
err = ROMlib_maperrno();
#endif
}
return err;
#endif
}
A2(PRIVATE, OSErr, serxhshake, LONGINT, fd, SerShk *, sershkp)
{
#if defined (MSDOS) || defined (CYGWIN32)
OSErr retval;
retval = serial_bios_serxhshake (fd, sershkp);
return retval;
#else
#if defined(TERMIO)
struct termio settings;
#else
struct sgttyb sgttyb;
struct tchars tchars;
#endif
OSErr err;
err = noErr;
#if defined(TERMIO)
if (ioctl(fd, TCGETA, &settings) < 0)
err = ROMlib_maperrno();
#else
if (ioctl(fd, TIOCGETP, &sgttyb) < 0 || ioctl(fd, TIOCGETC, &tchars) < 0)
err = ROMlib_maperrno();
#endif
else {
if (sershkp->fXOn) {
#if defined(TERMIO)
settings.c_iflag |= IXON;
} else
settings.c_iflag &= ~IXON;
#else
/* NB: LDECCTQ is left (un)set in the local mode word. */
tchars.t_startc = -1;
tchars.t_stopc = -1;
} else {
tchars.t_startc = sershkp->xOn;
tchars.t_stopc = sershkp->xOff;
}
#endif
if (sershkp->fInX) {
#if defined(TERMIO)
settings.c_iflag |= IXOFF;
} else
settings.c_iflag &= ~IXOFF;
err = ioctl(fd, TCSETAW, &settings) < 0 ? ROMlib_maperrno() : noErr;
#else
/* Can't enable TANDEM without setting startc & stopc. If I
* do that, input flow control is also enabled. This is what
* has been implemented here. The alternative is to refuse the
* request.
*/
sgttyb.sg_flags |= TANDEM;
tchars.t_startc = sershkp->xOn;
tchars.t_stopc = sershkp->xOff;
} else
sgttyb.sg_flags &= ~TANDEM;
if (ioctl(fd, TIOCSETP, &sgttyb) < 0 ||
ioctl(fd, TIOCSETC, &tchars) < 0)
err = ROMlib_maperrno();
#endif
}
return err;
#endif
}
A2(PRIVATE, OSErr, setbaud, LONGINT, fd, INTEGER, baud)
{
#if defined (MSDOS) || defined (CYGWIN32)
OSErr retval;
retval = serial_bios_setbaud (fd, baud);
return retval;
#else
#if defined(TERMIO)
struct termio settings;
#else
struct sgttyb sgttyb;
#endif
static INTEGER rates[] = {
50, 75, 110, 134, 150, 200, 300,
600, 1200, 1800, 2400, 4800, 9600, 19200,
38400, 32767,
}, *ip;
OSErr err;
for (ip = rates; *ip < baud ; ip++)
;
if (*ip == 32767 || ip[0] - baud > baud - ip[-1])
--ip;
#if defined(TERMIO)
if (ioctl(fd, TCGETA, &settings) < 0)
#else
if (ioctl(fd, TIOCGETP, &sgttyb) < 0)
#endif
err = ROMlib_maperrno();
else {
#if defined(TERMIO)
settings.c_cflag &= ~CBAUD;
settings.c_cflag |= ip - rates + 1;
err = ioctl(fd, TCSETAW, &settings) < 0 ? ROMlib_maperrno() : noErr;
#else
sgttyb.sg_ispeed = sgttyb.sg_ospeed = ip - rates + 1;
err = ioctl(fd, TIOCGETP, &sgttyb) < 0 ? ROMlib_maperrno() : noErr;
#endif
}
return err;
#endif
}
A2(PRIVATE, OSErr, ctlbrk, LONGINT, fd, INTEGER, flag)
{
#if defined (MSDOS) || defined (CYGWIN32)
OSErr retval;
retval = serial_bios_ctlbrk (fd, flag);
return retval;
#else
OSErr err;
#if defined(TERMIO)
if (flag == SER_START) {
/* NOTE: This will send a break for 1/4 sec */
err = ioctl(fd, TCSBRK, 0);
} else
err = noErr;
#else
err = ioctl(fd, flag == SER_START ? TIOCSBRK : TIOCCBRK, 0);
#endif
return err < 0 ? ROMlib_maperrno() : noErr;
#endif
}
A2(PRIVATE, OSErr, flow, LONGINT, fd, LONGINT, flag)
{
#if defined (MSDOS) || defined (CYGWIN32)
OSErr retval;
retval = serial_bios_setflow (fd, flag);
return retval;
#else
OSErr err;
#if defined(TERMIO)
#if !defined(__alpha)
err = ioctl(fd, TCXONC, flag == SER_STOP ? 0 : 1);
#else
err = ioctl(fd, TCXONC, (void *)(flag == SER_STOP ? 0L : 1L));
#endif
#else
err = ioctl(fd, flag == SER_STOP ? TIOCSTOP : TIOCSTART, 0);
#endif
return err < 0 ? ROMlib_maperrno() : noErr;
#endif
}
#define SERBAUDRATE 13
#define SERXHSHAKE 14 /* IMIV-226 */
#define SERMISC 16 /* IMIV-226 */
#define SERSETDTR 17 /* IMIV-226 */
#define SERCLRDTR 18 /* IMIV-226 */
#define SERCHAR 19
#define SERXCHAR 20 /* IMIV-226 */
#define SERUSETXOFF 21
#define SERUCLRXOFF 22
#define SERCXMITXON 23
#define SERUXMITXON 24
#define SERCXMITXOFF 25
#define SERUXMITXOFF 26
#define SERRESET 27
#define SERKILLIO 1
A2(PUBLIC, OSErr, ROMlib_serialctl, ParmBlkPtr, pbp, /* INTERNAL */
DCtlPtr, dcp)
{
OSErr err;
hiddenh h;
char c;
if (!(dcp->dCtlFlags & CWC(OPENBIT)))
err = notOpenErr;
else {
#if defined(SERIALDEBUG)
warning_trace_info ("serial control code = %d, param0 = 0x%x",
(LONGINT) CW(pbp->cntrlParam.csCode),
(LONGINT) (unsigned short) CW(pbp->cntrlParam.csParam[0]));
#endif
h = (hiddenh) MR(dcp->dCtlStorage);
switch (CW(pbp->cntrlParam.csCode)) {
case SERKILLIO:
err = noErr; /* All I/O done synchronously */
break;
case SERSET:
err = serset(HxX(h, fd), CW(pbp->cntrlParam.csParam[0]));
break;
case SERSETBUF:
err = noErr; /* ignored */
break;
case SERHSHAKE:
case SERXHSHAKE: /* NOTE: DTR handshake isn't supported */
err = serxhshake(HxX(h, fd), (SerShk *) pbp->cntrlParam.csParam);
break;
case SERSETBRK:
err = ctlbrk(HxX(h, fd), SER_START);
break;
case SERCLRBRK:
err = ctlbrk(HxX(h, fd), SER_STOP);
break;
case SERBAUDRATE:
err = setbaud(HxX(h, fd), CW(pbp->cntrlParam.csParam[0]));
break;
case SERMISC:
#if defined (MSDOS) || defined (CYGWIN32)
err = serial_bios_setdtr (HxX(h, fd));
#else
err = controlErr; /* not supported */
#endif
break;
case SERSETDTR:
#if defined (MSDOS) || defined (CYGWIN32)
err = serial_bios_clrdtr (HxX(h, fd));
#else
err = controlErr; /* not supported */
#endif
break;
case SERCLRDTR:
err = controlErr; /* not supported */
break;
case SERCHAR:
err = controlErr; /* not supported */
break;
case SERXCHAR:
err = controlErr; /* not supported */
break;
case SERUSETXOFF:
err = flow(HxX(h, fd), SER_STOP);
break;
case SERUCLRXOFF:
err = flow(HxX(h, fd), SER_START);
break;
case SERCXMITXON:
err = controlErr; /* not supported */
break;
case SERUXMITXON:
c = XONC;
err = write(HxX(h, fd), &c, 1) != 1 ? ROMlib_maperrno() : noErr;
break;
case SERCXMITXOFF:
err = controlErr; /* not supported */
break;
case SERUXMITXOFF:
c = XOFFC;
err = write(HxX(h, fd), &c, 1) != 1 ? ROMlib_maperrno() : noErr;
break;
case SERRESET:
err = controlErr; /* not supported */
break;
default:
err = controlErr;
break;
}
}
#if defined(SERIALDEBUG)
warning_trace_info ("serial control returning %d", (LONGINT) err);
#endif
DOCOMPLETION(pbp, err);
}
/*
* NOTE: SERSTATUS lies about everything except rdPend.
*/
A2(PUBLIC, OSErr, ROMlib_serialstatus, ParmBlkPtr, pbp, /* INTERNAL */
DCtlPtr, dcp)
{
OSErr err;
hiddenh h;
LONGINT n;
if (!(dcp->dCtlFlags & CWC(OPENBIT)))
err = notOpenErr;
else {
#if defined(SERIALDEBUG)
warning_trace_info ("serial status csCode = %d", (LONGINT) CW(pbp->cntrlParam.csCode));
#endif
h = (hiddenh) MR(dcp->dCtlStorage);
switch (CW(pbp->cntrlParam.csCode)) {
case SERGETBUF:
#if defined (LINUX) || defined (NEXTSTEP)
if (ioctl(HxX(h, fd), FIONREAD, &n) < 0)
#else
if (serial_bios_fionread(HxX(h, fd), &n) < 0)
#endif
err = ROMlib_maperrno();
else {
#if defined(SERIALDEBUG)
warning_trace_info ("serial status getbuf = %d", (LONGINT) n);
#endif
*(LONGINT *) pbp->cntrlParam.csParam = CL(n);
err = noErr;
}
break;
case SERSTATUS:
#if defined (LINUX) || defined (NEXTSTEP)
if (ioctl(HxX(h, fd), FIONREAD, &n) < 0)
#else
if (serial_bios_fionread (HxX(h, fd), &n) < 0)
#endif
err = ROMlib_maperrno();
else {
((SerStaRec *)pbp->cntrlParam.csParam)->cumErrs = 0;
((SerStaRec *)pbp->cntrlParam.csParam)->xOffSent = 0;
((SerStaRec *)pbp->cntrlParam.csParam)->rdPend = n>0 ? 1 : 0;
((SerStaRec *)pbp->cntrlParam.csParam)->wrPend = 0;
((SerStaRec *)pbp->cntrlParam.csParam)->ctsHold = 0;
((SerStaRec *)pbp->cntrlParam.csParam)->xOffHold = 0;
err = noErr;
}
break;
default:
err = statusErr;
break;
}
}
#if defined(SERIALDEBUG)
warning_trace_info ("serial status returning %d", (LONGINT) err);
#endif
DOCOMPLETION(pbp, err);
}
PRIVATE void restorecloseanddispose(hiddenh h)
{
#if defined (LINUX) || defined (NEXTSTEP)
#if defined(TERMIO)
ioctl(HxX(h, fd), TCSETAW, &HxX(h, state));
#else
ioctl(HxX(h, fd), TIOCSETP, &HxX(h, sgttyb));
ioctl(HxX(h, fd), TIOCSETC, &HxX(h, tchars));
ioctl(HxX(h, fd), TIOCLSET, &HxX(h, lclmode));
#endif
close(HxX(h, fd));
Uunlink(lockname);
#endif
DisposHandle((Handle) h);
}
A2(PUBLIC, OSErr, ROMlib_serialclose, ParmBlkPtr, pbp, /* INTERNAL */
DCtlPtr, dcp)
{
OSErr err;
hiddenh h;
if (dcp->dCtlFlags & CWC(OPENBIT)) {
h = (hiddenh) MR(dcp->dCtlStorage);
restorecloseanddispose(h);
dcp->dCtlFlags &= CWC(~OPENBIT);
err = noErr;
} else
err = notOpenErr;
#if defined(SERIALDEBUG)
warning_trace_info ("serial close returning %d", (LONGINT) err);
#endif
DOCOMPLETION(pbp, err);
}
#endif /* !defined (MACOSX) */