作者:FLandY1982
转自:http://blog.csdn.net/flandy1982/article/details/5175162
WINCE官方提供的串口驱动PDD层代码简单分析
作者:FLandY1982(flandy1982@sina.com)
日期:2010-1-11
版本:1.0
修改:
转载请注明出处:http://blog.csdn.net/FLandY1982/archive/2010/01/11/5175162.aspx
注意:
1.关于MDD层的代码详细分析,可以参考文章:http://blog.csdn.net/FLandY1982/archive/2009/12/24/5070059.aspx
2.文中所引用的代码,都在目录%WINCEROOT%/PUBLIC/COMMON/OAK/DRIVERS/SERIAL/下
3.开发者在实现PDD层时,可以直接继承CSerialPdd类,然后对相关的接口进行实现和重载,也可以直接实现PDD层函数,如果是直接实现PDD层函数本文第1章内容可以不用阅读。
1. PDD层代码简单分析
PDD层的主要包含了以下2个类:CSerialPDDPowerUpCallback, CSerialPDD, 下面简单的分析这2个类的作用。
1.1 CSerialPDDPowerUpCallback
CSerialPDDPowerUpCallback 类用于串口电源上电时的处理。
在调用CSerialPDD::Init()后会创建一个CSerialPDDPowerUpCallback类型的对象
在CSerialPDD::PowerOn()函数中会调用此对象的SignalCallBack()函数, 这样RunThread就开始运行, 进而通过调用CSerialPDD::NotifyPDDInterrupt()进行后续处理, 包括调用
CeEventHasOccurred (NOTIFICATION_EVENT_RS232_DETECTED, NULL) 通知系统有串口被探测到.
以及调用SerialEventHandler()进行MDD层上的处理.
更详细的细节可以参考微软的源代码:
%WINCEROOT%/PUBLIC/COMMON/OAK/DRIVERS/SERIAL/SERPDDCM/cserpdd.cpp
%WINCEROOT%/PUBLIC/COMMON/OAK/INC/cserpdd.h
2.2 CSerialPDD
CSerialPDD 是串口PDD层的关键,实现对硬件的操作,开发者开发的驱动就是继承这个类,并实现重载相关的函数来完成特定设备的PDD功能的。
这个类抽象了以下这些接口:
// Tx Function.
virtual BOOL InitXmit(BOOL bInit) = 0;
virtual void XmitInterruptHandler(PUCHAR pTxBuffer, ULONG *pBuffLen) = 0;
virtual void XmitComChar(UCHAR ComChar) = 0;
virtual BOOL EnableXmitInterrupt(BOOL bEnable)= 0;
virtual BOOL CancelXmit() = 0 ;
// Rx Function.
virtual BOOL InitReceive(BOOL bInit) = 0;
virtual ULONG ReceiveInterruptHandler(PUCHAR pRxBuffer,ULONG *pBufflen) = 0;
virtual ULONG CancelReceive() = 0;
// Modem
virtual BOOL InitModem(BOOL bInit) = 0;
virtual void ModemInterruptHandler()= 0; // This is Used to Indicate Modem Signal Changes.
virtual ULONG GetModemStatus() = 0;
virtual void SetDTR(BOOL bSet)= 0;
virtual void SetRTS(BOOL bSet)= 0;
virtual BOOL IsCTSOff() { return ((GetModemStatus() & MS_CTS_ON)==0) ; };
virtual BOOL IsDSROff() { return ((GetModemStatus() & MS_DSR_ON)==0) ; };
// Line Function
virtual BOOL InitLine(BOOL bInit) = 0;
virtual void LineInterruptHandler() = 0;
virtual void SetBreak(BOOL bSet) = 0 ;
virtual BOOL SetBaudRate(ULONG BaudRate,BOOL bIrModule) = 0;
virtual BOOL SetByteSize(ULONG ByteSize) = 0;
virtual BOOL SetParity(ULONG Parity)= 0;
virtual BOOL SetStopBits(ULONG StopBits)= 0;
以上这些接口都是纯虚函数, 在实现PDD层时, 必须实现这些接口.
当然不需要的功能你可以简单的用类似virtual BOOL func() {;} 的形式来实现。
其他的非纯虚函数的虚函数也可以被用户重载, 以实现自己特定的功能。
我们知道PDD层的函数为如下函数:
This function returns a pointer to a HWOBJ structure. The structure contains the function pointers and parameters for the hardware interface functions of the relevant lower layer. | |
This function clears an RS-232 line break condition. | |
This function clears the Data Terminal Ready (DTR) signal. | |
This function clears the Request to Send (RTS) signal. | |
This function closes the device initialized by the HWInit function. | |
This function is called by the upper layer to de-initialize the hardware when a device driver is unloaded. | |
This function disables the infrared (IR) serial interface. | |
This function enables the infrared (IR) serial interface. | |
This function retrieves the current properties of the communications device. | |
This function returns the current interrupt type. | |
This function retrieves the modem status. | |
This function returns the maximum number of bytes that the hardware buffer can hold, not including the padding, stop, and start bits. | |
This function returns the start of the hardware-receive buffer. | |
This function specifies the hardware status API. | |
This function initializes a serial device. | |
This function executes device I/O control (IOCTL) routines. | |
This function handles line interrupts for serial port devices. | |
This function handles the modem interrupt. In the serial port upper layer implementation available in Microsoft Windows CE 3.0 and later, this function replaces the HWOtherIntrHandler function. | |
This function is called by the upper layer to open the serial device. | |
In Windows CE 3.0 and later, this function has been replaced with the new function HWModemIntrHandler. | |
This function performs necessary operations after it initializes all data structures and prepares the serial IST to begin handling interrupts. It is called by the upper layer. | |
This function notifies the platform-dependent driver that the hardware platform is about to enter suspend mode. It is called by the model device driver (MDD). | |
This function notifies the platform-dependent driver that the hardware platform is resuming from suspend mode. It is called by the MDD. | |
This function purges the communications device. | |
This function writes bytes to hardware. The driver calls this function. | |
This function resets the hardware API. | |
This function handles serial port interrupts. | |
This function sets the line break condition on the transmit line. | |
This function sets the communications time-out events in response to a call to the SetCommTimeouts function. | |
This function sets the device control block. | |
This function sets the Data Terminal Ready (DTR) signal. | |
This function sets the Request to Send (RTS) signal. | |
This function handles the transmit interrupt for serial port devices. | |
This function transmits a single character. |
更具体的细节可以参考:MSDN帮助 ms-help://MS.WindowsCE.500/wceddk5/html/wce50grfserialportdriverfunctions.htm
微软用一堆SerXXXXX()的函数封装了CSerialPdd相关的操作,来完成PDD功能。
2. PDD与MDD层的交互
2.1 PDD层的函数是如何能够被MDD层所调用
1.2节介绍的那一堆SerXXXXX()函数会被记录到一个函数指针表里,真是通过这个函数指针表来实现与MDD层的交互的。此函数指针表是HW_VTBL类型的, 在微软的代码里是命名为IoVTbl的函数指针表。
MDD层通过调用 GetSerialObject(DWORD DeviceArrayIndex)函数来获取一个HWOBJ结构的指针, 这个结构包含以下成员:
ULONG BindFlags; // Flags controlling MDD behaviour. Se above.
DWORD dwIntID; // Interrupt Identifier used if THREAD_AT_INIT or THREAD_AT_OPEN
PHW_VTBL pFuncTbl;
其中pFuncTbl正是指向我们之前说到的 IoVTbl 函数指针结构的地址.
这样MDD层就可以通过->pFuncTbl.DDSIFunction()来对特定的硬件做特定的操作了.
2.2 GetSerialObject函数
这个函数的原型是:PHWOBJ GetSerialObject(DWORD DeviceArrayIndex) ,它是连接MDD和PDD层的关键函数, 也是实现多端口驱动的关键, 这个函数允许一个MDD层连接多个PDD层。
在MDD层的COM_Init函数中,驱动会通过查询DeviceArrayIndex键值, 得到我们需要打开的是普通串口或者是其他种类的串口设备。
而正是这个数值决定了GetSerialObject是返回哪个串口的PHWOBJ指针, PHWOBJ包含了pFuncTbl,这个正是前一节说到的PDD层函数指针表,通过这个函数表我们就可以实现对相应的串口设备进行操作。(串口有可能是标准的串口,也有可能是红外设备)
2.3 CreateSerialObject 函数
如果开发者选择直接继承微软CSerialPdd类来实现串口的PDD层,还要实现CreateSerialObject及DeleteSerialObject函数。
在MDD层的COM_Init函数被调用时,驱动会通过查询注册表来得到相关参数并调用PDD层的HWInit函数,HWInit函数又会调用CreateSerialObject来初始化串口设备,在关闭串口以后DeleteSerialObject函数会被调用。
3. 其他
3.1 COM_Init函数如何被调用
此函数通常是由Device.exe进程调用的, 而此函数的参数Identifier 是一个指向注册表HKEY_LOCAL_MACHINE/Drivers/Active.下的一个键值,这也是决定驱动如何操作硬件的关键。
对于使用ActivateDeviceEx函数调用的情况,请参照MSND, http://msdn.microsoft.com/en-us/library/aa447677.aspx
3.2 相关代码段:
[cpp]
view plain
copy
- HANDLE
-
- COM_Init(
-
- ULONG Identifier
-
- )
-
- {
-
- PVOID pHWHead = NULL;
-
- PHW_INDEP_INFO pSerialHead = NULL;
-
- ULONG HWBufferSize;
-
- DWORD DevIndex;
-
- HKEY hKey;
-
- ULONG kreserved = 0, kvaluetype;
-
- ULONG datasize = sizeof(ULONG);
-
-
-
- /*
-
- * INTERNAL: this routine initializes the hardware abstraction interface
-
- * via HWInit(). It allocates a data structure representing this
-
- * instantiation of the device. It also creates an event and initializes
-
- * a critical section for receiving as well as registering the logical
-
- * interrupt dwIntID with NK via InterruptInitialize. This call
-
- * requires that the hardware dependent portion export apis that return
-
- * the physical address of the receive buffer and the size of that buffer.
-
- * Finally, it creates a buffer to act as an intermediate
-
- * buffer when receiving.
-
- */
-
- DEBUGMSG (ZONE_INIT | ZONE_FUNCTION, (TEXT("+COM_Init/r/n")));
-
-
-
- // Allocate our control structure.
-
- pSerialHead = (PHW_INDEP_INFO)LocalAlloc(LPTR, sizeof(HW_INDEP_INFO));
-
-
-
- // Check that LocalAlloc did stuff ok too.
-
- if ( !pSerialHead ) {
-
- DEBUGMSG(ZONE_INIT | ZONE_ERROR,
-
- (TEXT("Error allocating memory for pSerialHead, COM_Init failed/n/r")));
-
- return(NULL);
-
- }
-
-
-
- // Initially, open list is empty.
-
- InitializeListHead( &pSerialHead->OpenList );
-
- InitializeCriticalSection(&(pSerialHead->OpenCS));
-
- pSerialHead->pAccessOwner = NULL;
-
- pSerialHead->fEventMask = 0;
-
-
-
- // Init CommTimeouts.
-
- pSerialHead->CommTimeouts.ReadIntervalTimeout = READ_TIMEOUT;
-
- pSerialHead->CommTimeouts.ReadTotalTimeoutMultiplier =
-
- READ_TIMEOUT_MULTIPLIER;
-
- pSerialHead->CommTimeouts.ReadTotalTimeoutConstant =
-
- READ_TIMEOUT_CONSTANT;
-
- pSerialHead->CommTimeouts.WriteTotalTimeoutMultiplier= 0;
-
- pSerialHead->CommTimeouts.WriteTotalTimeoutConstant = 0;
-
-
-
- /* Create tx and rx events and stash in global struct field. Check return.
-
- */
-
- pSerialHead->hSerialEvent = CreateEvent(0,FALSE,FALSE,NULL);
-
- pSerialHead->hKillDispatchThread = CreateEvent(0, FALSE, FALSE, NULL);
-
- pSerialHead->hTransmitEvent = CreateEvent(0, FALSE, FALSE, NULL);
-
- pSerialHead->hReadEvent = CreateEvent(0, FALSE, FALSE, NULL);
-
-
-
- if ( !pSerialHead->hSerialEvent || !pSerialHead->hKillDispatchThread ||
-
- !pSerialHead->hTransmitEvent || !pSerialHead->hReadEvent ) {
-
- DEBUGMSG(ZONE_ERROR | ZONE_INIT,
-
- (TEXT("Error creating event, COM_Init failed/n/r")));
-
- LocalFree(pSerialHead);
-
- return(NULL);
-
- }
-
-
-
- /* Initialize the critical sections that will guard the parts of
-
- * the receive and transmit buffers.
-
- */
-
- InitializeCriticalSection(&(pSerialHead->ReceiveCritSec1));
-
- InitializeCriticalSection(&(pSerialHead->TransmitCritSec1));
-
-
-
- /* Want to use the Identifier to do RegOpenKey and RegQueryValue (?)
-
- * to get the index to be passed to GetHWObj.
-
- * The HWObj will also have a flag denoting whether to start the
-
- * listening thread or provide the callback.
-
- */
-
- DEBUGMSG (ZONE_INIT,(TEXT("Try to open %s/r/n"), (LPCTSTR)Identifier));
-
- hKey = OpenDeviceKey((LPCTSTR)Identifier);
-
- // 通过调用OpenDeviceKey, 驱动可以通过Identifier找到驱动的注册表键的所在.
-
- if ( !hKey ) {
-
- DEBUGMSG (ZONE_INIT | ZONE_ERROR,
-
- (TEXT("Failed to open devkeypath, COM_Init failed/r/n")));
-
- LocalFree(pSerialHead);
-
- return(NULL);
-
- }
-
-
-
- datasize = sizeof(DWORD);
-
- // 通过查询DeviceArrayIndex键值, 我们可以知道需要打开的是普通串口或者是其他类型的串口设备.
-
- if ( RegQueryValueEx(hKey, L"DeviceArrayIndex", NULL, &kvaluetype,
-
- (LPBYTE)&DevIndex, &datasize) ) {
-
- DEBUGMSG (ZONE_INIT | ZONE_ERROR,
-
- (TEXT("Failed to get DeviceArrayIndex value, COM_Init failed/r/n")));
-
- RegCloseKey (hKey);
-
- LocalFree(pSerialHead);
-
- return(NULL);
-
- }
-
-
-
- datasize = sizeof(DWORD);
-
- // 通过查询Priority256键值, 我们可以知道IST的优先级, 在后面会通过这个值来改变IST的优先级.
-
- if ( RegQueryValueEx(hKey, L"Priority256", NULL, &kvaluetype,
-
- (LPBYTE)&pSerialHead->Priority256, &datasize) ) {
-
- pSerialHead->Priority256 = DEFAULT_CE_THREAD_PRIORITY;
-
- DEBUGMSG (ZONE_INIT | ZONE_WARN,
-
- (TEXT("Failed to get Priority256 value, defaulting to %d/r/n"), pSerialHead->Priority256));
-
- }
-
-
-
- RegCloseKey (hKey);
-
-
-
- DEBUGMSG (ZONE_INIT,
-
- (TEXT("DevIndex %X/r/n"), DevIndex));
-
-
-
- // Initialize hardware dependent data.
-
- // GetSerialObject是连接MDD和PDD层的关键函数, 在这个函数里面决定了DevIndex是对什么设备进行操作.
-
- // 可能是标准的串口, 也可能是红外接口
-
- pSerialHead->pHWObj = GetSerialObject( DevIndex );
-
- if ( !pSerialHead->pHWObj ) {
-
- DEBUGMSG(ZONE_ERROR | ZONE_INIT,
-
- (TEXT("Error in GetSerialObject, COM_Init failed/n/r")));
-
- LocalFree(pSerialHead);
-
- return(NULL);
-
- }
-
-
-
- DEBUGMSG (ZONE_INIT, (TEXT("About to call HWInit(%s,0x%X)/r/n"),
-
- Identifier, pSerialHead));
-
- // 这里调用了PDD层的HWInit
-
- pHWHead = pSerialHead->pHWObj->pFuncTbl->HWInit(Identifier, pSerialHead, pSerialHead->pHWObj);
-
- pSerialHead->pHWHead = pHWHead;
-
-
-
- /* Check that HWInit did stuff ok. From here on out, call Deinit function
-
- * when things fail.
-
- */
-
- if ( !pHWHead ) {
-
- DEBUGMSG (ZONE_INIT | ZONE_ERROR,
-
- (TEXT("Hardware doesn't init correctly, COM_Init failed/r/n")));
-
- COM_Deinit(pSerialHead);
-
- return(NULL);
-
- }
-
- DEBUGMSG (ZONE_INIT,
-
- (TEXT("Back from hardware init/r/n")));
-
-
-
- // Allocate at least twice the hardware buffer size so we have headroom
-
- HWBufferSize = 2 * pSerialHead->pHWObj->pFuncTbl->HWGetRxBufferSize(pHWHead);
-
-
-
- // Init rx buffer and buffer length here.
-
- pSerialHead->RxBufferInfo.Length =
-
- HWBufferSize > RX_BUFFER_SIZE ? HWBufferSize:RX_BUFFER_SIZE;
-
-
-
- pSerialHead->RxBufferInfo.RxCharBuffer =
-
- LocalAlloc(LPTR, pSerialHead->RxBufferInfo.Length);
-
-
-
- if ( !pSerialHead->RxBufferInfo.RxCharBuffer ) {
-
- DEBUGMSG(ZONE_INIT|ZONE_ERROR,
-
- (TEXT("Error allocating receive buffer, COM_Init failed/n/r")));
-
- COM_Deinit(pSerialHead);
-
- return(NULL);
-
- }
-
-
-
- DEBUGMSG (ZONE_INIT, (TEXT("RxHead init'ed/r/n")));
-
-
-
- RxResetFifo(pSerialHead);
-
-
-
- InitializeCriticalSection(&(pSerialHead->RxBufferInfo.CS));
-
- InitializeCriticalSection(&(pSerialHead->TxBufferInfo.CS));
-
- DEBUGMSG (ZONE_INIT, (TEXT("RxBuffer init'ed with start at %x/r/n"),
-
- pSerialHead->RxBufferInfo.RxCharBuffer));
-
-
-
- if ( pSerialHead->pHWObj->BindFlags & THREAD_AT_INIT ) {
-
- // Hook the interrupt and start the associated thread.
-
- if ( ! StartDispatchThread( pSerialHead ) ) {
-
- // Failed on InterruptInitialize or CreateThread. Bail.
-
- COM_Deinit(pSerialHead);
-
- return(NULL);
-
- }
-
-
-
- }
-
-
-
- // OK, now that everything is ready on our end, give the PDD
-
- // one last chance to init interrupts, etc.
-
- (void) pSerialHead->pHWObj->pFuncTbl->HWPostInit( pHWHead );
-
-
-
- DEBUGMSG (ZONE_INIT | ZONE_FUNCTION, (TEXT("-COM_Init/r/n")));
-
- return(pSerialHead);
-
- }
- HANDLE
- COM_Init(
- ULONG Identifier
- )
- {
- PVOID pHWHead = NULL;
- PHW_INDEP_INFO pSerialHead = NULL;
- ULONG HWBufferSize;
- DWORD DevIndex;
- HKEY hKey;
- ULONG kreserved = 0, kvaluetype;
- ULONG datasize = sizeof(ULONG);
- /*
- * INTERNAL: this routine initializes the hardware abstraction interface
- * via HWInit(). It allocates a data structure representing this
- * instantiation of the device. It also creates an event and initializes
- * a critical section for receiving as well as registering the logical
- * interrupt dwIntID with NK via InterruptInitialize. This call
- * requires that the hardware dependent portion export apis that return
- * the physical address of the receive buffer and the size of that buffer.
- * Finally, it creates a buffer to act as an intermediate
- * buffer when receiving.
- */
- DEBUGMSG (ZONE_INIT | ZONE_FUNCTION, (TEXT("+COM_Init/r/n")));
- // Allocate our control structure.
- pSerialHead = (PHW_INDEP_INFO)LocalAlloc(LPTR, sizeof(HW_INDEP_INFO));
- // Check that LocalAlloc did stuff ok too.
- if ( !pSerialHead ) {
- DEBUGMSG(ZONE_INIT | ZONE_ERROR,
- (TEXT("Error allocating memory for pSerialHead, COM_Init failed/n/r")));
- return(NULL);
- }
- // Initially, open list is empty.
- InitializeListHead( &pSerialHead->OpenList );
- InitializeCriticalSection(&(pSerialHead->OpenCS));
- pSerialHead->pAccessOwner = NULL;
- pSerialHead->fEventMask = 0;
- // Init CommTimeouts.
- pSerialHead->CommTimeouts.ReadIntervalTimeout = READ_TIMEOUT;
- pSerialHead->CommTimeouts.ReadTotalTimeoutMultiplier =
- READ_TIMEOUT_MULTIPLIER;
- pSerialHead->CommTimeouts.ReadTotalTimeoutConstant =
- READ_TIMEOUT_CONSTANT;
- pSerialHead->CommTimeouts.WriteTotalTimeoutMultiplier= 0;
- pSerialHead->CommTimeouts.WriteTotalTimeoutConstant = 0;
- /* Create tx and rx events and stash in global struct field. Check return.
- */
- pSerialHead->hSerialEvent = CreateEvent(0,FALSE,FALSE,NULL);
- pSerialHead->hKillDispatchThread = CreateEvent(0, FALSE, FALSE, NULL);
- pSerialHead->hTransmitEvent = CreateEvent(0, FALSE, FALSE, NULL);
- pSerialHead->hReadEvent = CreateEvent(0, FALSE, FALSE, NULL);
- if ( !pSerialHead->hSerialEvent || !pSerialHead->hKillDispatchThread ||
- !pSerialHead->hTransmitEvent || !pSerialHead->hReadEvent ) {
- DEBUGMSG(ZONE_ERROR | ZONE_INIT,
- (TEXT("Error creating event, COM_Init failed/n/r")));
- LocalFree(pSerialHead);
- return(NULL);
- }
- /* Initialize the critical sections that will guard the parts of
- * the receive and transmit buffers.
- */
- InitializeCriticalSection(&(pSerialHead->ReceiveCritSec1));
- InitializeCriticalSection(&(pSerialHead->TransmitCritSec1));
- /* Want to use the Identifier to do RegOpenKey and RegQueryValue (?)
- * to get the index to be passed to GetHWObj.
- * The HWObj will also have a flag denoting whether to start the
- * listening thread or provide the callback.
- */
- DEBUGMSG (ZONE_INIT,(TEXT("Try to open %s/r/n"), (LPCTSTR)Identifier));
- hKey = OpenDeviceKey((LPCTSTR)Identifier);
- // 通过调用OpenDeviceKey, 驱动可以通过Identifier找到驱动的注册表键的所在.
- if ( !hKey ) {
- DEBUGMSG (ZONE_INIT | ZONE_ERROR,
- (TEXT("Failed to open devkeypath, COM_Init failed/r/n")));
- LocalFree(pSerialHead);
- return(NULL);
- }
- datasize = sizeof(DWORD);
- // 通过查询DeviceArrayIndex键值, 我们可以知道需要打开的是普通串口或者是其他类型的串口设备.
- if ( RegQueryValueEx(hKey, L"DeviceArrayIndex", NULL, &kvaluetype,
- (LPBYTE)&DevIndex, &datasize) ) {
- DEBUGMSG (ZONE_INIT | ZONE_ERROR,
- (TEXT("Failed to get DeviceArrayIndex value, COM_Init failed/r/n")));
- RegCloseKey (hKey);
- LocalFree(pSerialHead);
- return(NULL);
- }
- datasize = sizeof(DWORD);
- // 通过查询Priority256键值, 我们可以知道IST的优先级, 在后面会通过这个值来改变IST的优先级.
- if ( RegQueryValueEx(hKey, L"Priority256", NULL, &kvaluetype,
- (LPBYTE)&pSerialHead->Priority256, &datasize) ) {
- pSerialHead->Priority256 = DEFAULT_CE_THREAD_PRIORITY;
- DEBUGMSG (ZONE_INIT | ZONE_WARN,
- (TEXT("Failed to get Priority256 value, defaulting to %d/r/n"), pSerialHead->Priority256));
- }
- RegCloseKey (hKey);
- DEBUGMSG (ZONE_INIT,
- (TEXT("DevIndex %X/r/n"), DevIndex));
- // Initialize hardware dependent data.
- // GetSerialObject是连接MDD和PDD层的关键函数, 在这个函数里面决定了DevIndex是对什么设备进行操作.
- // 可能是标准的串口, 也可能是红外接口
- pSerialHead->pHWObj = GetSerialObject( DevIndex );
- if ( !pSerialHead->pHWObj ) {
- DEBUGMSG(ZONE_ERROR | ZONE_INIT,
- (TEXT("Error in GetSerialObject, COM_Init failed/n/r")));
- LocalFree(pSerialHead);
- return(NULL);
- }
- DEBUGMSG (ZONE_INIT, (TEXT("About to call HWInit(%s,0x%X)/r/n"),
- Identifier, pSerialHead));
- // 这里调用了PDD层的HWInit
- pHWHead = pSerialHead->pHWObj->pFuncTbl->HWInit(Identifier, pSerialHead, pSerialHead->pHWObj);
- pSerialHead->pHWHead = pHWHead;
- /* Check that HWInit did stuff ok. From here on out, call Deinit function
- * when things fail.
- */
- if ( !pHWHead ) {
- DEBUGMSG (ZONE_INIT | ZONE_ERROR,
- (TEXT("Hardware doesn't init correctly, COM_Init failed/r/n")));
- COM_Deinit(pSerialHead);
- return(NULL);
- }
- DEBUGMSG (ZONE_INIT,
- (TEXT("Back from hardware init/r/n")));
- // Allocate at least twice the hardware buffer size so we have headroom
- HWBufferSize = 2 * pSerialHead->pHWObj->pFuncTbl->HWGetRxBufferSize(pHWHead);
- // Init rx buffer and buffer length here.
- pSerialHead->RxBufferInfo.Length =
- HWBufferSize > RX_BUFFER_SIZE ? HWBufferSize:RX_BUFFER_SIZE;
- pSerialHead->RxBufferInfo.RxCharBuffer =
- LocalAlloc(LPTR, pSerialHead->RxBufferInfo.Length);
- if ( !pSerialHead->RxBufferInfo.RxCharBuffer ) {
- DEBUGMSG(ZONE_INIT|ZONE_ERROR,
- (TEXT("Error allocating receive buffer, COM_Init failed/n/r")));
- COM_Deinit(pSerialHead);
- return(NULL);
- }
- DEBUGMSG (ZONE_INIT, (TEXT("RxHead init'ed/r/n")));
- RxResetFifo(pSerialHead);
- InitializeCriticalSection(&(pSerialHead->RxBufferInfo.CS));
- InitializeCriticalSection(&(pSerialHead->TxBufferInfo.CS));
- DEBUGMSG (ZONE_INIT, (TEXT("RxBuffer init'ed with start at %x/r/n"),
- pSerialHead->RxBufferInfo.RxCharBuffer));
- if ( pSerialHead->pHWObj->BindFlags & THREAD_AT_INIT ) {
- // Hook the interrupt and start the associated thread.
- if ( ! StartDispatchThread( pSerialHead ) ) {
- // Failed on InterruptInitialize or CreateThread. Bail.
- COM_Deinit(pSerialHead);
- return(NULL);
- }
- }
- // OK, now that everything is ready on our end, give the PDD
- // one last chance to init interrupts, etc.
- (void) pSerialHead->pHWObj->pFuncTbl->HWPostInit( pHWHead );
- DEBUGMSG (ZONE_INIT | ZONE_FUNCTION, (TEXT("-COM_Init/r/n")));
- return(pSerialHead);
- }