📄 bvd_udc_ser.c
字号:
PCF_INTTIMEOUTS |
PCF_SPECIALCHARS |
PCF_TOTALTIMEOUTS |
PCF_XONXOFF;
pHWHead->CommProp.dwSettableBaud =
BAUD_075 | BAUD_110 | BAUD_150 | BAUD_300 | BAUD_600 |
BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
BAUD_7200 | BAUD_9600 | BAUD_14400 |
BAUD_19200 | BAUD_38400 | BAUD_56K | BAUD_128K |
BAUD_115200 | BAUD_57600 | BAUD_USER;
pHWHead->CommProp.dwSettableParams =
SP_BAUD | SP_RLSD ;
pHWHead->CommProp.wSettableData =
DATABITS_8;
pHWHead->CommProp.wSettableStopParity =
STOPBITS_10 | STOPBITS_20 |
PARITY_NONE | PARITY_ODD | PARITY_EVEN | PARITY_SPACE |
PARITY_MARK;
pHWHead->fIRMode = FALSE; // Select wired by default
// Here is where we do any actual init for the hardware. In the case of
// USB function, we mostly just validate the hardware and then enable
// interrupts. When we detect the presence of the bus, GetIntr will take
// care of identifying us to the host and kicking things off.
SA_USB_Init(pHWHead);
DEBUGMSG (ZONE_INIT|ZONE_FUNCTION,
(TEXT("-SerInit - %X\r\n"),
pHWHead ));
return (pHWHead);
ALLOCFAILED:
// Unmap any memory areas that we may have mapped.
if ( pHWHead->pUDCRegs)
VirtualFree((PVOID)pHWHead->pUDCRegs, 0, MEM_RELEASE);
if ( pHWHead->pINTCRegs)
VirtualFree((PVOID)pHWHead->pINTCRegs, 0, MEM_RELEASE);
LocalFree(pHWHead);
//RETAILMSG(1, (TEXT("SerInit - Exiting with ERROR\r\n")))
// Free any critical sections we have allocated
DeleteCriticalSection(&(pHWHead->TransmitCritSec));
DeleteCriticalSection(&(pHWHead->HwRegCritSec));
// And free the context data structure
LocalFree(pHWHead);
DEBUGMSG (ZONE_INIT|ZONE_FUNCTION,
(TEXT("-SerInit - %X\r\n"),
pHWHead ));
return (NULL);
}
/*
@doc OEM
@func PVOID | SerPostInit | Performs final hardware initialization.
*
*/
static
BOOL SerPostInit(
PVOID pHead // @parm PVOID returned by SerInit.
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DEBUGMSG( ZONE_INIT|ZONE_FUNCTION,
(TEXT("SerPostInit+\r\n")));
// We use a PDD specific thread, rather than the default thread provided
// by the MDD.
StartEventThread( pHWHead );
return TRUE;
}
/*
@doc OEM
@func PVOID | SerDeinit | Deinitializes device identified by argument.
* This routine frees any memory allocated by SerInit.
*
*/
static
BOOL SerDeinit(
PVOID pHead // @parm PVOID returned by SerInit.
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DEBUGMSG( ZONE_INIT|ZONE_FUNCTION,
(TEXT("+SerDeinit\r\n")));
if ( !pHWHead )
return (FALSE);
// Make sure device is closed before doing DeInit
if ( pHWHead->cOpenCount )
SerClose( pHead );
SA_USB_DeInit(pHWHead);
if ( pHWHead->pUDCRegs)
VirtualFree((PVOID)pHWHead->pUDCRegs, 0, MEM_RELEASE);
if ( pHWHead->pINTCRegs)
VirtualFree((PVOID)pHWHead->pINTCRegs, 0, MEM_RELEASE);
// Free any critical sections we have allocated
DeleteCriticalSection(&(pHWHead->TransmitCritSec));
DeleteCriticalSection(&(pHWHead->HwRegCritSec));
// Free the HWObj allocated in GetSerialObject
LocalFree(pHWHead->pHWObj);
LocalFree(pHWHead);
DEBUGMSG( ZONE_INIT|ZONE_FUNCTION,
(TEXT("-SerDeinit\r\n")));
return (TRUE);
}
/*
@doc OEM
@func BOOL | SerOpen | This routine is called when the port is opened.
* Not exported to users, only to driver.
*
@rdesc Returns TRUE if successful, FALSEotherwise.
*/
static
BOOL SerOpen(
PVOID pHead /*@parm PVOID returned by Serinit. */
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DEBUGMSG( ZONE_INIT | ZONE_FUNCTION,
(TEXT("SerOpen+\r\n")));
// Disallow multiple simultaneous opens
if ( pHWHead->cOpenCount )
return (FALSE);
pHWHead->cOpenCount++;
return (TRUE);
}
/*
@doc OEM
@func ULONG | SerClose | This routine closes the device
* identified by the PVOID returned by SerInit.
* Not exported to users, only to driver.
*
@rdesc The return value is 0.
*/
static
ULONG SerClose(
PVOID pHead // @parm PVOID returned by SerInit.
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DEBUGMSG (ZONE_CLOSE | ZONE_FUNCTION,
(TEXT("+SerClose\r\n")));
if ( pHWHead->cOpenCount ) {
DEBUGMSG (ZONE_CLOSE,
(TEXT("SerClose, closing device\r\n")));
pHWHead->cOpenCount--;
#ifdef TODO
// Do we need something similar on USB???
// while we are still transmitting, sleep.
uTries = 0;
while ( ((pHWHead->ser16550.IER = READ_PORT_UCHAR(pHWHead->ser16550.pIER))
& SERIAL_IER_THR) && // indicates TX in progress
(uTries++ < 100) && // safety net
// indicates FIFO not yet empty
!(pHWHead->ser16550.LSR & SERIAL_LSR_TEMT)
) {
DEBUGMSG (ZONE_CLOSE,
(TEXT("SerClose, TX in progress, IER 0x%X, LSR 0x%X\r\n"),
*pHWHead->ser16550.pIER, pHWHead->ser16550.LSR));
Sleep(10);
}
#endif
// TODO - When the device is closed, should power it down or somehow try to
// let the desktop know that we aren't doing anything with any data that it
// might be sending our way..
// NOTE - Depending on your chipset, you may need to power down the
// USB chipset here. Check your datasheets.
// Do we want to disable the UDC (UDE=0) at this point?
// or is it enough on Cable Disconnect? Not sure how Com_Open relates with
// USB Serial Host driver...
//
}
DEBUGMSG (ZONE_CLOSE | ZONE_FUNCTION,
(TEXT("-SerClose\r\n")));
return (0);
}
// @doc OEM
// @func ULONG | SerRxIntr | This routine gets several characters from the hardware
// receive buffer and puts them in a buffer provided via the second argument.
// It returns the number of bytes lost to overrun.
//
// @rdesc The return value indicates the number of overruns detected.
// The actual number of dropped characters may be higher.
//
static
ULONG SerRxIntr(
PVOID pHead, // @parm Pointer to hardware head
PUCHAR pRxBuffer, // @parm Pointer to receive buffer
ULONG *pBufflen // @parm In = max bytes to read, out = bytes read
)
{
// PSER16550_INFO pHWHead = (PSER16550_INFO)pHead;
PSER_INFO pHWHead = (PSER_INFO)pHead;
ULONG RetVal = 0;
ULONG TargetRoom = *pBufflen;
BOOL fRXFlag = FALSE;
BOOL fReplaceparityErrors = FALSE;
BOOL fNull;
UCHAR cEvtChar;
PUCHAR pRxOrig = pRxBuffer;
DEBUGMSG (ZONE_FUNCTION,
(TEXT("+SerRxIntr %d\r\n"),
*pBufflen));
cEvtChar = pHWHead->dcb.EvtChar;
fNull = pHWHead->dcb.fNull;
if( pHWHead->dcb.fErrorChar && pHWHead->dcb.fParity )
fReplaceparityErrors = TRUE;
//NKDbgPrintfW(TEXT("LenInRx: %02d\r\n"), *pBufflen);
// Protect the following from collision on hardware registers.
// In particular, we can't let anyone else do SA_USB_ accesses between
// time we set the read address and time we do the actual read in
// the loop below.
EnterCriticalSection(&(pHWHead->HwRegCritSec));
fRXFlag = SA_USB_RxIntHandler(pHWHead, pRxBuffer, pBufflen);
LeaveCriticalSection(&(pHWHead->HwRegCritSec));
//NKDbgPrintfW(TEXT("LenOutRx: %02d\r\n"), *pBufflen);
// if we saw one (or more) EVT chars, then generate an event
if( fRXFlag )
{
// NKDbgPrintfW(TEXT("EvCh: %02x\r\n"), pHWHead->dcb.EvtChar);
EvaluateEventFlag( pHWHead->pMddHead, EV_RXFLAG );
}
#ifdef DEBUG
if( ZONE_RXDATA )
CELOGDATA(1, CELID_RAW_UCHAR, pRxOrig, (WORD)*pBufflen, 1, CELZONE_MISC);
#endif
DEBUGMSG (ZONE_WARN|ZONE_READ,
(TEXT("-SerRxIntr - rx %d, drop %d.\r\n"),
*pBufflen,
pHWHead->DroppedBytes));
RetVal = pHWHead->DroppedBytes;
pHWHead->DroppedBytes = 0;
return RetVal;
}
//
// @doc OEM
// @func PVOID | SerGetRxStart | This routine returns the start of the hardware
// receive buffer. See SerGetRxBufferSize.
//
// @rdesc The return value is a pointer to the start of the device receive buffer.
//
static
PVOID SerGetRxStart(
PVOID pHead // @parm PVOID returned by Serinit.
)
{
DEBUGMSG (ZONE_FUNCTION,
(TEXT("SerGetRxStart\r\n")));
return NULL;
}
//
// @doc OEM
// @func ULONG | SerGetInterruptType | This function is called
// by the MDD whenever an interrupt occurs. The return code
// is then checked by the MDD to determine which of the four
// interrupt handling routines are to be called.
//
// @rdesc This routine returns a bitmask indicating which interrupts
// are currently pending.
//
static
INTERRUPT_TYPE SerGetInterruptType(
PVOID pHead // Pointer to hardware head
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
INTERRUPT_TYPE interrupts = 0;
DEBUGMSG (ZONE_FUNCTION,
(TEXT("+SerGetInterruptType 0x%X\r\n"), pHead));
DEBUGMSG( ZONE_THREAD, (TEXT("Stat %X, Addr %X, dConfIdx %X\r\n"),
pHWHead->cIntStat,
pHWHead->dAddress,
pHWHead->dConfIdx));
interrupts = SA_USB_GetInterruptType(pHWHead);
DEBUGMSG (ZONE_FUNCTION,
(TEXT("-SerGetInterruptType 0x%X, 0x%X\r\n"),
pHead, interrupts));
return interrupts;
}
//
// @doc OEM
// @func ULONG | SerModemIntr | This routine is called from the MDD
// whenever INTR_MODEM is returned by SerGetInterruptType.
//
// @rdesc None
//
static
VOID SerModemIntr(
PVOID pHead // Hardware Head
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DWORD dwModemStatus;
dwModemStatus = pHWHead->ModemStatus;
DEBUGMSG (ZONE_FUNCTION,
(TEXT("SerModemIntr+\r\n")));
ServiceEP0(pHWHead, &dwModemStatus);
if ( pHWHead->dConfIdx ) {
if ( pHWHead->cOpenCount) {
// If open, notify app of any control line changes.
DEBUGMSG (ZONE_EVENTS,
(TEXT("Modem Status %2.2X <> %2.2X\r\n"),
pHWHead->ModemStatus, dwModemStatus));
if( (pHWHead->ModemStatus & MS_DSR_ON) != (dwModemStatus & MS_DSR_ON) )
EvaluateEventFlag(pHWHead->pMddHead, EV_DSR);
if( (pHWHead->ModemStatus & MS_CTS_ON) != (dwModemStatus & MS_CTS_ON) )
EvaluateEventFlag(pHWHead->pMddHead, EV_CTS);
if( (pHWHead->ModemStatus & MS_RLSD_ON) != (dwModemStatus & MS_RLSD_ON) )
EvaluateEventFlag(pHWHead->pMddHead, EV_RLSD);
} else {
// If RLSD transitioned to active, we need to generate event.
if( (dwModemStatus & MS_RLSD_ON) &&
!(pHWHead->ModemStatus & MS_RLSD_ON) ) {
if ( IsAPIReady(SH_WMGR) ) {
CeEventHasOccurred (NOTIFICATION_EVENT_RS232_DETECTED, NULL);
}
DEBUGMSG (1|ZONE_EVENTS,
(TEXT("Indicated RS232 Cable Event\r\n")));
}
}
}
pHWHead->ModemStatus = dwModemStatus;
}
//
// @doc OEM
// @func ULONG | SerLineIntr | This routine is called from the MDD
// whenever INTR_LINE is returned by SerGetInterruptType.
//
// @rdesc None
//
static
VOID SerLineIntr(
PVOID pHead // Hardware Head
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DEBUGMSG (ZONE_FUNCTION,
(TEXT("SerLineIntr\r\n")));
// USB serial doesn't have a concept of anything like the LSR.
// But since a bus reset is what we sort of equate to DCD, I use
// this routine to handle USB reset conditions.
//
// Note that by the time we get here with an SA_USB , we are actually
// plugged back into the bus.
//
SA_USB_LineIntHandler(pHWHead); // Re-initialize the hardware
}
//
// @doc OEM
// @func ULONG | SerGetRxBufferSize | This function returns
// the size of the hardware buffer passed to the interrupt
// initialize function. It would be used only for devices
// which share a buffer between the MDD/PDD and an ISR.
//
//
// @rdesc This routine always returns 0 for 16550 UARTS.
//
static
ULONG SerGetRxBufferSize(
PVOID pHead
)
{
DEBUGMSG (ZONE_FUNCTION,
(TEXT("SerGetRxBufferSize\r\n")));
//Change default buffer size
return 0x2000;
//return 0;
}
//
// @doc OEM
// @func ULONG | SerTXIntr | This routine is called from the new MDD
// whenever INTR_TX is returned by SerGetInterruptType. It is responsible
// for loading up the TX FIFO with next block of data.
//
// @rdesc None
//
static
VOID SerTxIntr(
PVOID pHead, // Hardware Head
PUCHAR pTxBuffer, // @parm Pointer to receive buffer
ULONG *pBuffLen // @parm In = max bytes to transmit,
// out = bytes transmitted
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DEBUGMSG (ZONE_WRITE|ZONE_FUNCTION,
(TEXT("SerTxIntr+\r\n")));
pHWHead->CommErrors &= ~CE_TXFULL;
// Go send the data.
SA_USB_TxIntHandler(pHWHead, pTxBuffer, pBuffLen);
DEBUGMSG (ZONE_WRITE|ZONE_FUNCTION,
(TEXT("SerTxIntr-, %d bytes\r\n"),
*pBuffLen));
}
/*
@doc OEM
@func BOOL | SerPowerOff |
* Called by driver to turn off power to serial port.
* Not exported to users, only to driver.
*
@rdesc This routine returns a status.
*/
static
BOOL SerPowerOff(
PVOID pHead // @parm PVOID returned by SerInit.
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
/* Note: No debug messages in power handlers! */
SA_USB_PowerOff(pHWHead);
return (TRUE);
}
/*
@doc OEM
@func BOOL | SerPowerOn |
* Called by driver to turn on power to serial port.
* Not exported to users, only to driver.
*
@rdesc This routine returns a status.
*/
static
BOOL SerPowerOn(
PVOID pHead // @parm PVOID returned by SerInit.
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
/* Note: No debug messages in power handlers! */
SA_USB_PowerOn(pHWHead);
return (TRUE);
}
//
// @doc OEM
// @func void | SerClearDtr | This routine clears DTR.
//
// @rdesc None.
//
static
VOID SerClearDTR(
PVOID pHead // @parm PVOID returned by HWinit.
)
{
DEBUGMSG (ZONE_FUNCTION,
(TEXT("SerClearDTR, 0x%X\r\n"),
pHead));
// We don't support DTR emulation.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -