📄 sc2440_usb_ser.c
字号:
@doc OEM
@func VOID | SerClearRTS | This routine clears RTS.
@rdesc None.
**************************************************************************/
static
VOID SerClearRTS( PVOID pHead ) // @parm PVOID returned by HWinit.
{
DEBUGMSG(1, (TEXT("SerClearRTS, 0x%X\r\n"), pHead));
// We don't support RTS emulation.
}
/*************************************************************************
@doc OEM
@func VOID | SerSetRTS | This routine sets RTS.
@rdesc None.
**************************************************************************/
static
VOID SerSetRTS( PVOID pHead ) // @parm PVOID returned by HWinit.
{
DEBUGMSG(1, (TEXT("SerSetRTS, 0x%X\r\n"), pHead));
// We don't support RTS emulation.
}
/*************************************************************************
@doc OEM
@func BOOL | SerEnableIR | This routine enables ir.
Not exported to users, only to driver.
@rdesc Returns TRUE if successful, FALSEotherwise.
**************************************************************************/
static
BOOL SerEnableIR( PVOID pHead, // @parm PVOID returned by Serinit.
ULONG BaudRate ) // @parm PVOID returned by HWinit.
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DEBUGMSG(1, (TEXT("SerEnableIR, 0x%X\r\n"), pHead));
// We don't support an IR mode, so fail.
return (FALSE);
}
/*************************************************************************
@doc OEM
@func BOOL | SerDisableIR | This routine disable the ir.
Not exported to users, only to driver.
@rdesc Returns TRUE if successful, FALSEotherwise.
**************************************************************************/
static
BOOL SerDisableIR( PVOID pHead ) // @parm PVOID returned by Serinit.
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DEBUGMSG(1, (TEXT("SerDisableIR, 0x%X\r\n"), pHead));
// We don't support an IR mode. But don't fail, in case
// someone calls this redundantly to ensure that we are
// in wired mode, which is what we support.
return (TRUE);
}
/*************************************************************************
@doc OEM
@func VOID | SerClearBreak | This routine clears break.
@rdesc None.
*************************************************************************/
static
VOID SerClearBreak( PVOID pHead ) // @parm PVOID returned by HWinit.
{
DEBUGMSG(1, (TEXT("SerClearBreak, 0x%X\r\n"), pHead));
// We don't have a concept of break over USB serial
}
/*************************************************************************
@doc OEM
@func VOID | SerSetBreak | This routine sets break.
@rdesc None.
*************************************************************************/
static
VOID SerSetBreak( PVOID pHead ) // @parm PVOID returned by HWinit.
{
DEBUGMSG(1, (TEXT("SerSetBreak, 0x%X\r\n"), pHead));
// We don't have a concept of break over USB serial
}
/*************************************************************************
@doc OEM
@func BOOL | SerXmitComChar | Transmit a char immediately
@rdesc TRUE if succesful
*************************************************************************/
static
BOOL SerXmitComChar( PVOID pHead, // @parm PVOID returned by HWInit.
UCHAR ComChar ) // @parm Character to transmit.
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DEBUGMSG(1, (TEXT("+SerXmitComChar 0x%X\r\n"), pHead));
// Get critical section, then transmit when buffer empties
DEBUGMSG(1, (TEXT("XmitComChar wait for CritSec %x.\r\n"),
&(pHWHead->TransmitCritSec)));
EnterCriticalSection(&(pHWHead->TransmitCritSec));
DEBUGMSG(1, (TEXT("XmitComChar got CritSec %x.\r\n"),
&(pHWHead->TransmitCritSec)));
try
{
// TODO - We need to wait for the current transmit to finish and
// then sneak this data in ahead of whatever else is queued.
#ifdef TODO
while( TRUE ) // We know THR will eventually empty
{
// Write the character if we can
ReadLSR( pHWHead );
if( pHWHead->LSR & SERIAL_LSR_THRE )
{
OUTB(pHWHead, pData, ComChar);
DEBUGMSG(1, (TEXT("XmitComChar wrote x%X\r\n"), ComChar));
break;
}
// If we couldn't write the data yet, then wait for a
// TXINTR to come in and try it again.
// Enable xmit intr.
OUTB(pHWHead, pIER, IER_NORMAL_INTS | SERIAL_IER_THR);
// Wait until the txintr has signalled.
DEBUGMSG(1, (TEXT("XmitComChar WaitIntr x%X\r\n"),
pHWHead->FlushDone));
WaitForSingleObject(pHWHead->FlushDone, (ULONG)1000);
}
#else
DEBUGMSG (0, (TEXT("!!! SerXmitComChar 0x%X not implemented\r\n"),
pHead));
#endif
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Just exit
}
LeaveCriticalSection(&(pHWHead->TransmitCritSec));
DEBUGMSG(1, (TEXT("XmitComChar released CritSec %x.\r\n"),
&(pHWHead->TransmitCritSec)));
DEBUGMSG(1, (TEXT("-SerXmitComChar 0x%X\r\n"), pHead));
return TRUE;
}
/*************************************************************************
@doc OEM
@func ULONG | SerGetStatus | This structure is called by the MDD
to retrieve the contents of a COMSTAT structure.
@rdesc The return is a ULONG, representing success (0) or failure (-1).
*************************************************************************/
static
ULONG SerGetStatus( PVOID pHead, // @parm PVOID returned by HWInit.
LPCOMSTAT lpStat )// Pointer to LPCOMMSTAT to hold status.
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
ULONG RetVal = pHWHead->CommErrors;
DEBUGMSG(1, (TEXT("++SerGetStatus 0x%X\r\n"), pHead));
pHWHead->CommErrors = 0; // Clear old errors each time
// We don't emulate any of this, so always return a fixed result.
if (lpStat)
{
// TODO - Make sure we return reasonable results here.
pHWHead->Status.fCtsHold = 0;
pHWHead->Status.fDsrHold = 0;
pHWHead->Status.cbInQue = 0;
pHWHead->Status.cbOutQue = 0;
}
else
RetVal = (ULONG)-1;
DEBUGMSG(1, (TEXT("--SerGetStatus 0x%X\r\n"), pHead));
return RetVal;
}
/*************************************************************************
@doc OEM
@func ULONG | SerReset | Perform any operations associated
with a device reset
@rdesc None.
*************************************************************************/
static
VOID SerReset( PVOID pHead ) // @parm PVOID returned by HWInit.
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DEBUGMSG(1, (TEXT("++SerReset 0x%X\r\n"), pHead));
memset(&pHWHead->Status, 0, sizeof(COMSTAT));
// TODO - Is there anything special we need to do here.
DEBUGMSG(1, (TEXT("--SerReset 0x%X\r\n"), pHead));
}
/*************************************************************************
@doc OEM
@func VOID | SerGetModemStatus | Retrieves modem status.
@rdesc None.
*************************************************************************/
static
VOID SerGetModemStatus( PVOID pHead, // @parm PVOID returned by HWInit.
PULONG pModemStatus ) // @parm PULONG passed in by user.
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DEBUGMSG(1, (TEXT("++SerGetModemStatus 0x%X\r\n"), pHead));
*pModemStatus = pHWHead->ModemStatus;
DEBUGMSG (0, (TEXT("--SerGetModemStatus 0x%X (stat x%X) \r\n"),
pHead,
*pModemStatus));
return;
}
/*************************************************************************
@doc OEM
@func VOID | SerGetCommProperties | Retrieves Comm Properties.
@rdesc None.
*************************************************************************/
static
VOID SerGetCommProperties(
PVOID pHead, // @parm PVOID returned by SerInit.
LPCOMMPROP pCommProp ) // @parm Pointer to receive COMMPROP structure.
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DEBUGMSG(1, (TEXT("SerGetCommProperties 0x%X\r\n"), pHead));
*pCommProp = pHWHead->CommProp;
return;
}
/*************************************************************************
@doc OEM
@func VOID | SerPurgeComm | Purge RX and/or TX
@rdesc None.
*************************************************************************/
static
VOID SerPurgeComm( PVOID pHead, // @parm PVOID returned by HWInit.
DWORD fdwAction ) // @parm Action to take.
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DEBUGMSG(1, (TEXT("++SerPurgeComm 0x%X\r\n"), pHead));
EnterCriticalSection(&(pHWHead->HwRegCritSec));
if ( (fdwAction & PURGE_TXCLEAR) || (fdwAction & PURGE_TXABORT) )
{
// Abort any pending TX data. The MDD takes care of aborting
// data pended in the driver. All I can do to stop an IN that
// has already been queued is to Un-Arm this endpoint, causing
// subsequent INs to get naked. If the IN transfer has started,
// its not clear I can stop it in progress.
// In addition to NAKing host, clearing ARM tells TxIntr that he
// can use the buffer for the next write that comes down.
#if TODO
ucECR = SC2440_USB_Read(pHWHead, EP1AControl);
ucECR &= 0xFE; // Clear the ARM bit.
SC2440_USB_Write(pHWHead, EP1AControl, ucECR );
#endif
}
if ( (fdwAction & PURGE_RXCLEAR) || (fdwAction & PURGE_RXABORT) ) {
#if TODO
// Abort any pending RX data.
SC2440_USB_Write(pHWHead, IntStatus, 0x04 ); // Clear the EP2 interrupt
SC2440_USB_Write(pHWHead, EP2AControl, 0x03); // Reenable the endpoint
#endif
}
LeaveCriticalSection(&(pHWHead->HwRegCritSec));
DEBUGMSG(1,
(TEXT("--SerPurgeComm 0x%X\r\n"), pHead));
return;
}
/************************************************************************
@doc OEM
@func BOOL | SerSetDCB | Sets new values for DCB. This
routine gets a DCB from the MDD. It must then compare
this to the current DCB, and if any fields have changed take
appropriate action.
@rdesc BOOL
************************************************************************/
static
BOOL SerSetDCB( PVOID pHead, // @parm PVOID returned by HWInit.
LPDCB lpDCB ) // @parm Pointer to DCB structure
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
BOOL bRet;
DEBUGMSG(1, (TEXT("++SerSetDCB 0x%X\r\n"), pHead));
bRet = TRUE;
// If the device is open, scan for changes and do whatever
// is needed for the changed fields. if the device isn't
// open yet, just save the DCB for later use by the open.
if( pHWHead->OpenCount )
{
#ifdef TODO
// We don't really support any of this. Ignore for now
// Note, fparity just says whether we should check
// receive parity. And the 16550 won't let us NOT
// check parity if we generate it. So this field
// has no effect on the hardware.
if ( lpDCB->BaudRate != pHWHead->dcb.BaudRate )
{
bRet = SerSetBaudRate( pHWHead, lpDCB->BaudRate );
}
if ( bRet && (lpDCB->ByteSize != pHWHead->dcb.ByteSize ))
{
bRet = SerSetByteSize( pHWHead, lpDCB->ByteSize );
}
if ( bRet && (lpDCB->Parity != pHWHead->dcb.Parity ))
{
bRet = SerSetParity( pHWHead, lpDCB->Parity );
}
if ( bRet && (lpDCB->StopBits != pHWHead->dcb.StopBits ))
{
bRet = SerSetStopBits( pHWHead, lpDCB->StopBits );
}
// Don't worry about fOutxCtsFlow. It is a flag which
// will be examined every time we load the TX buffer.
// No special action required here.
#endif
}
if (bRet)
{
// Now that we have done the right thing, store this DCB
pHWHead->dcb = *lpDCB;
}
DEBUGMSG(1, (TEXT("--SerSetDCB 0x%X\r\n"), pHead));
return bRet;
}
/*************************************************************************
@doc OEM
@func BOOL | SerSetCommTimeouts | Sets new values for the
CommTimeouts structure. routine gets a DCB from the MDD. It
must then compare this to the current DCB, and if any fields
have changed take appropriate action.
@rdesc ULONG
*************************************************************************/
static
ULONG SerSetCommTimeouts(
PVOID pHead, // @parm PVOID returned by HWInit.
LPCOMMTIMEOUTS lpCommTimeouts ) // @parm Pointer to CommTimeout structure
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
ULONG retval = 0;
DEBUGMSG(1, (TEXT("++SerSetCommTimeout 0x%X\r\n"), pHead));
// OK, first check for any changes and act upon them
if( lpCommTimeouts->WriteTotalTimeoutMultiplier !=
pHWHead->CommTimeouts.WriteTotalTimeoutMultiplier )
{
}
// Now that we have done the right thing, store this DCB
pHWHead->CommTimeouts = *lpCommTimeouts;
DEBUGMSG(1, (TEXT("--SerSetCommTimeout 0x%X\r\n"), pHead));
return retval;
}
/*************************************************************************
@doc OEM
@func BOOL | SerIoctl | Device IO control routine.
@parm DWORD | dwOpenData | value returned from COM_Open call
@parm DWORD | dwCode | io control code to be performed
@parm PBYTE | pBufIn | input data to the device
@parm DWORD | dwLenIn | number of bytes being passed in
@parm PBYTE | pBufOut | output data from the device
@parm DWORD | dwLenOut |maximum number of bytes to receive from device
@parm PDWORD | pdwActualOut | actual number of bytes received from device
@rdesc Returns TRUE for success, FALSE for failure
@remark The MDD will pass any unrecognized IOCTLs through to this function.
*************************************************************************/
static
BOOL SerIoctl(PVOID pHead, DWORD dwCode,PBYTE pBufIn,DWORD dwLenIn,
PBYTE pBufOut,DWORD dwLenOut,PDWORD pdwActualOut)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
BOOL RetVal = TRUE;
DEBUGMSG(1, (TEXT("++SerIoctl 0x%X\r\n"), pHead));
switch (dwCode)
{
// Currently, no defined IOCTLs
default:
RetVal = FALSE;
DEBUGMSG(1, (TEXT(" Unsupported ioctl 0x%X\r\n"), dwCode));
break;
}
DEBUGMSG(1, (TEXT("--SerIoctl 0x%X\r\n"), pHead));
return(RetVal);
}
const
HW_VTBL IoVTbl = {
SerInit,
SerPostInit,
SerDeinit,
SerOpen,
SerClose,
SerGetInterruptType,
SerRxIntr,
SerTxIntr,
SerModemIntr,
SerLineIntr,
SerGetRxBufferSize,
SerPowerOff,
SerPowerOn,
SerClearDTR,
SerSetDTR,
SerClearRTS,
SerSetRTS,
SerEnableIR,
SerDisableIR,
SerClearBreak,
SerSetBreak,
SerXmitComChar,
SerGetStatus,
SerReset,
SerGetModemStatus,
SerGetCommProperties,
SerPurgeComm,
SerSetDCB,
SerSetCommTimeouts,
SerIoctl};
extern const HW_VTBL SerCardIoVTbl;
PHWOBJ
GetSerialObject( DWORD DeviceArrayIndex )
{
PHWOBJ pSerObj;
// We do not have a statically allocated array of HWObjs. Instead, we
// allocate a new HWObj for each instance of the driver. The MDD will
// always call GetSerialObj/HWInit/HWDeinit in that order, so we can do
// the alloc here and do any subsequent free in HWDeInit.
// Allocate space for the HWOBJ.
pSerObj = (PHWOBJ)LocalAlloc( LPTR, sizeof(HWOBJ) );
if ( !pSerObj )
return (NULL);
// Fill in the HWObj structure that we just allocated.
pSerObj->BindFlags = THREAD_IN_PDD; // We take care of our own IST
pSerObj->dwIntID = SYSINTR_USBD; // SysIntr
pSerObj->pFuncTbl = (HW_VTBL *) &IoVTbl; // Return pointer to functions
// Now return this structure to the MDD.
return (pSerObj);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -