📄 commdrv.c
字号:
long WriteByteC(U32 device, unsigned char b)
{
U32 erc, counter;
U8 *pXBuf;
erc = 0;
pXBuf = pSendBuf[device];
counter = comstat[device].XTimeOut; /* set up for timeout */
while (cSendBuf[device] == sSendBuf[device]) {
Sleep(1);
counter--;
if (!counter)
return (ErcXmitTimeout); /* never got sent */
}
#asm
CLI
#endasm
if (!fExpectInt[device]) { /* Xmit buf empty, send ourself */
OutByte(b, THR[device]);
fExpectInt[device] = TRUE;
}
else {
pXBuf[head_send[device]] = b;
if (++head_send[device] == sSendBuf[device])
head_send[device] = 0;
++cSendBuf[device]; /* one more in buf */
}
#asm
STI
#endasm
return (erc);
}
/********************************************/
long WriteRecordC(U32 device,
unsigned char *pSendData,
unsigned int cbSendData)
{
int erc;
erc = 0;
while ((cbSendData) && (!erc)) {
erc = WriteByteC(device, *pSendData++);
--cbSendData;
}
return (erc);
}
/********************************************/
long DiscardRecvC(U32 device)
{
U32 saveto, erc;
U8 b;
saveto = comstat[device].RTimeOut;
comstat[device].RTimeOut = 1;
erc = 0;
while (!erc)
erc = ReadByteC(device, &b);
comstat[device].RTimeOut = saveto;
return (0);
}
/********************************************
This sets comms params prior to opening, or
while a channel is in use.
********************************************/
U32 SetParams(U32 device)
{
U32 divisor, speed;
U8 c, parity, bits, stop_bit, temp;
parity = comstat[device].parity;
bits = comstat[device].databits;
stop_bit = comstat[device].stopbits;
speed = comstat[device].Baudrate;
/* Set up baud rate */
divisor = 115200/speed;
#asm
CLI
#endasm
c=InByte (LCR[device]);
OutByte ((c | 0x80), LCR[device]);
OutByte ((divisor & 0x00ff), DLAB_LO[device]);
OutByte (((divisor>>8) & 0x00ff), DLAB_HI[device]);
OutByte (c, LCR[device]);
#asm
STI
#endasm
/* set coms params */
temp = bits - 5;
temp |= ((stop_bit == 1) ? 0x00 : 0x04);
switch (parity)
{
case NO_PAR : temp |= 0x00; break;
case OD_PAR : temp |= 0x08; break;
case EV_PAR : temp |= 0x18; break;
}
#asm
CLI
#endasm
OutByte (temp, LCR[device]);
#asm
STI
#endasm
return (0);
}
/********************************************
This allocates buffers, sets up the ISR
and IRQ values and open the channel for use.
*********************************************/
U32 OpenCommC(U32 device)
{
U32 erc;
U16 port_base;
if (comstat[device].commJob)
return(ErcChannelOpen);
GetJobNum(&comstat[device].commJob);
erc = AllocOSPage(comstat[device].XBufSize/4096,
&pSendBuf[device]);
if (!erc) {
erc = AllocOSPage(comstat[device].RBufSize/4096,
&pRecvBuf[device]);
if (erc) /* get rid of Xmit buf if we can't recv */
DeAllocPage(pSendBuf[device],
comstat[device].XBufSize/4096);
}
if (erc) {
comstat[device].commJob = 0;
return (erc);
}
port_base = comstat[device].IOBase;
/* Set up buffer variables for this port */
cSendBuf[device] = 0;
head_send[device] = 0;
tail_send[device] = 0;
cRecvBuf[device] = 0;
head_recv[device] = 0;
tail_recv[device] = 0;
recv_error[device] = 0;
THR[device] = port_base;
IER[device] = port_base + 1;
IIR[device] = port_base + 2;
LCR[device] = port_base + 3;
MCR[device] = port_base + 4;
LSR[device] = port_base + 5;
MSR[device] = port_base + 6;
DLAB_HI[device] = port_base + 1;
DLAB_LO[device] = port_base;
InByte(THR[device]); /* reset any pending ints on chip */
InByte(LSR[device]);
#asm
CLI
#endasm
control_byte[device] = RTS | DTR | OUT2;
OutByte(control_byte[device], MCR[device]); /* Mod Ctrl Reg */
OutByte(0x0F, IER[device]); /* Int Enable Reg */
#asm
STI
#endasm
SetParams(device);
UnMaskIRQ(comstat[device].IRQNum);
return (0);
}
/********************************************
This closes the port, sets the owner to 0
and deallocates the buffers.
********************************************/
int CloseCommC (U32 device)
{
U32 Job, erc;
MaskIRQ(comstat[device].IRQNum);
OutByte(0, MCR[device]);
OutByte(0, IER[device]);
erc = DeAllocPage(pSendBuf[device],
comstat[device].XBufSize/4096);
erc = DeAllocPage(pRecvBuf[device],
comstat[device].RBufSize/4096);
comstat[device].commJob = 0;
return (erc);
}
/***************************************************************************
Now begins the PUBLIC routines that are interfaced to for all DEVICE DRIVERS
****************************************************************************/
/******************************************
Called for all device operations. This
assigns physical device from logical number
that outside callers use. For RS-232, 5=0
and 6=1.
*******************************************/
U32 comdev_op(U32 dDevice,
U32 dOpNum,
U32 dLBA,
U32 dnBlocks,
U8 *pData)
{
U32 erc;
U32 Job, device;
U8 c;
/* Set internal drive number */
/* 5 RS-232 1 COM1 (OS built-in) */
/* 6 RS-232 2 COM2 (OS built-in) */
if (dDevice == 5)
device = 0;
else
device = 1;
GetJobNum(&Job);
if ((!comstat[device].commJob) && (dOpNum != CmdOpenC))
return(ErcNotOpen);
if (comstat[device].commJob) {
if ((comstat[device].commJob != Job) &&
(Job != 1))
return(ErcNotOwner);
}
erc = 0; /* default error */
switch(dOpNum) {
case(0):
break; /* Null Command */
case CmdReadB:
erc = ReadByteC(device, pData);
break;
case CmdWriteB:
erc = WriteByteC(device, *pData);
break;
case CmdReadRec:
erc = ReadRecordC(device, pData, dnBlocks,
&comstat[device].LastTotal);
break;
case CmdWriteRec:
erc = WriteRecordC(device, pData, dnBlocks);
break;
case CmdSetRTO:
comstat[device].RTimeOut = dLBA; /* 10ms intervals */
break;
case CmdSetXTO:
comstat[device].XTimeOut = dLBA; /* 10ms intervals */
break;
case CmdOpenC:
erc = OpenCommC(device);
break;
case CmdCloseC:
erc = CloseCommC(device);
break;
case CmdDiscardRcv:
erc = DiscardRecvC(device);
break;
case CmdSetDTR:
control_byte[device] |= DTR;
OutByte(control_byte[device], LCR[device]);
break;
case CmdSetRTS:
control_byte[device] |= RTS;
OutByte(control_byte[device], MCR[device]);
break;
case CmdReSetDTR:
control_byte[device] &= ~DTR;
OutByte(control_byte[device], LCR[device]);
case CmdReSetRTS:
control_byte[device] &= ~RTS;
OutByte(control_byte[device], MCR[device]);
break;
case CmdBreak:
c = InByte(LCR[device]);
OutByte((c | 0x40), LCR[device]);
Sleep(dLBA);
OutByte(c, LCR[device]);
break;
case CmdGetDC:
*pData = mstat_byte[device] & CD;
break;
case CmdGetDSR:
*pData = mstat_byte[device] & DSR;
break;
case CmdGetCTS:
*pData = mstat_byte[device] & CTS;
break;
case CmdGetRI:
*pData = mstat_byte[device] & RI;
break;
default:
break;
}
comstat[device].LastErc = erc;
return(erc);
}
/******************************************
Called for status report on coms channel.
Returns 64 byte block for channel specified.
This is called by the PUBLIC call DeviceStat
*******************************************/
U32 comdev_stat(U32 dDevice,
S8 *pStatRet,
U32 dStatusMax,
U32 *pdStatusRet)
{
U32 i, j, device;
/* Set internal device number */
if (dDevice == 5)
device = 0;
else device = 1;
if (dStatusMax > 64)
i = 64;
else
i = dStatusMax;
if (!device){
CopyData(&comstat[0], pStatRet, i); /* copy the status data */
}
else {
CopyData(&comstat[1], pStatRet, i); /* copy the status data */
}
*pdStatusRet = dStatusMax; /* give em the size returned */
return(0);
}
/******************************************
Called to set parameters for the comms
channels prior to opening or while in use.
If an invalid value is passed in, all params
remain the same as before.
Some comms channel params may not be changed
while the channel is in use.
This is called by the PUBLIC call DeviceInit.
*******************************************/
S32 comdev_init(U32 dDevice,
S8 *pInitData,
U32 sdInitData)
{
U32 erc, Xbufsize, Rbufsize, device;
U32 speed, XTO, RTO;
U16 port_base;
U8 parity, bits, stop_bit, IRQNUM;
if (dDevice == 5)
device = 0; /* Set internal device number */
else
device = 1;
pCS = pInitData;
/* Get the callers new params */
speed = pCS->Baudrate; /* Non Volatile */
parity = pCS->parity; /* Non Volatile */
bits = pCS->databits; /* Non Volatile */
stop_bit = pCS->stopbits; /* Non Volatile */
XTO = pCS->XTimeOut; /* Non Volatile */
RTO = pCS->RTimeOut; /* Non Volatile */
port_base = pCS->IOBase;
Xbufsize = pCS->XBufSize;
Rbufsize = pCS->RBufSize;
IRQNUM = pCS->IRQNum;
/* Non Volatile params can be set whether or not the
channel is open. Do these first and return errors. */
if ((speed > MAX_BAUD) || (speed < MIN_BAUD))
return (ErcBadBaud);
if ((parity < NO_PAR) || (parity > OD_PAR))
return (ErcBadParity);
if ((bits < 5) || (bits > 8))
return (ErcBadDataBits);
if ((stop_bit < 1) || (stop_bit > 2))
return (ErcBadStopBits);
if (!XTO) XTO = 1;
if (!RTO) RTO = 1;
comstat[device].Baudrate = speed;
comstat[device].parity = parity;
comstat[device].databits = bits;
comstat[device].stopbits = stop_bit;
comstat[device].XTimeOut = XTO;
comstat[device].RTimeOut = RTO;
/* If we got here, the params are OK. Now we check
to see if the channel is open and call SetParams
if so. The channel is open if the JobNumber
in the commstat record is NON-ZERO.
*/
if (comstat[device].commJob) { /* Channel Open! */
SetParams(device);
}
/* Channel is not open so we check and set rest of params */
else {
if (!port_base)
return (ErcBadIOBase);
if (IRQNUM < 3)
return (ErcBadCommIRQ);
/* We now round up buffer sizes to whole pages */
Xbufsize = Xbufsize/4096 * 4096;
if (Xbufsize % 4096) Xbufsize+=4096; /* another page */
Rbufsize = Rbufsize/4096 * 4096;
if (Rbufsize % 4096) Rbufsize+=4096; /* another page */
comstat[device].IOBase = port_base;
comstat[device].IRQNum = IRQNUM;
comstat[device].XBufSize = Xbufsize;
comstat[device].RBufSize = Rbufsize;
/* Local copies so we don't work from a structure in ISR */
sSendBuf[device] = Xbufsize; /* Size of buffer (allocated) */
sRecvBuf[device] = Rbufsize; /* Size of buffer (allocated) */
erc = 0;
}
return(erc);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -