Wince serial port driver analysis

Source: Internet
Author: User

Although serial communication is a common standard and widely known, some of the content involved in the driver may not be very commonly used in common applications, here, we will give a brief introduction to the Code which will be coherent later.
The serial communication interface is one of the most popular communication interfaces. The simplicity of its electrical interface makes it widely used in the computer field. The serial communication interface mentioned here mainly refers to UART (Universal Serial) and IrDA. Generally, there are 3-wire and 9wire connections in a serial connection. The connection mode of 3wire defines three connections: send, receive, and ground. It is used for sending and receiving, just like the name. The following figure shows the structure of a 3-wire connection.
 

Generally, there are two FIFO buffers on the serial interface controller for receiving and sending. After receiving the data, the received data is directly placed in the buffer, at the same time, the control circuit sends a notification to the local bus so that the local bus can read the data in the buffer, so as to respond (wait and read) the data can still be received through the buffer. The sending and sending process is just the opposite. The local bus can write data directly to the sending buffer until the device is filled up without waiting for each data sending. This is the basic sending and receiving process (this part of the logical process is most familiar to everyone ). This is the same in 3wire and 9wire. However, we consider the following situation. If the recipient's response suffers interference for some reason (for example, when the processor is occupied by other interrupted services), it may not be enough. Previously, receivefifo may be filled up, in this way, the data sent in the future will be lost, and the disadvantages of serial communication will be shown when reliable data transmission is required. If you need reliable data transmission, you need to control the transmission and receiving of data streams. Define a serial connection as follows in 9wire.
Needle number
1
2
3
4
5
6
7
8
9

Abbreviations
DCD
Rxd
Txd
DTr
Gnd
DSR
RTS
CTS
Dell

Function Description
Data Carrier Detection
Receive data
Send data
Data Terminal ready
Signal Location
Data device ready
Send request
Clear sending
Ringing indicator

 

That is to say, six control lines including DCD, DTR, DSR, RTS, CTS, and Dell are added on the basis of the original 3wire. Here, RTS/CTS is used for traffic control, and DCD and Dell are used for connection modem. With a dedicated hardware traffic control pin, the traffic control becomes possible to complete matching between the two ends of the transmission and receiving so that data can be reliably transmitted. When you use the RTS/CTS (request sending/clearing sending) traffic control, you should connect the RTS and CTS lines at both ends of the communication ). before sending data, set the request to send (RTS) to send the request line. If the receiving end is ready for receiving, start the CTS (clear to send) lead of the response. In this way, sending and receiving dual-transmission enters the data transmission status. If the receiving end processes data at a lower speed than the sending end, at the receiving end, you can also set the CTS lead to restore the originally blocked state to temporarily interrupt data transmission, and then restore the data transmission to the CTS state if necessary. In this way, UART transmission achieves flow control and ensures the completeness of data transmission.
Here, we also want to talk about software throttling. Although the hardware can complete the flow control task, but when it is limited by the number of connections, the hardware throttling cannot be used, and a special software flow control method is designed. Now back to the 3-line transmission scenario, if the load of the buffer reaches a certain limit when the receiving end receives data (that is, leave a certain buffer space) when the receiving end sends a special flag (receiving stop bit) to the sending end, when the sending end receives the mark, it stops sending, after the acceptor buffer is lower than the other limit, it sends a flag (receiving permit bit) to the sender, which can control the transmission start and stop of the data stream. This kind of software Throttling is done by leaving a margin for the buffer. It is not suitable for sending and receiving dual-end processors with Low Speed. Therefore, hardware Throttling is required.

The other pins are related to the modem. The data set ready of the DSR data device is used to indicate that the modem is in usable state. Data Terminal ready indicates that the data terminal can be used. These two signals are used to check whether the modem is connected. This pin is set by the modem when the Dell pin has a phone dial. The DCD signal is set when the modem receives the digital carrier signal. It is used to learn about the received signal of the modem.

For the remaining parity and stop bit settings, you only need to set the registers without software interference. Next let's look at the specific driver.

Architecture

In wince, the serial port driver has a fixed model. The serial port model in CE follows the ISO/OSI Network Communication Model (Layer 7), that is, the serial port is part of the CE network module. The RS232 interface (or other physical media) implements the physical layer of the network, while the driver and serialapi constitute the data link layer. Other parts are not defined. In typical applications, serialapi and indirectly use TAPI or directly interact with ActiveSync to form part of the CE network. The protocols of infrared itself are much more complex. It has a special set of models to describe its usage rules, so it cannot go deeper without much understanding of infrared devices. On this side of the serial port, the entire driver model is also quite complex, but fortunately, the driver only uses the serialapi layer, at which level the serial port behavior is relatively simple.

Here we only involve the serial/IrDA driver mentioned above (the green part ). In the driver routine provided by wince, the serial/infrared driver adopts a hierarchical structure design. MDD provides framework implementation and provides the basic implementation required by the OS, the code design has nothing to do with the specific hardware design. PDD provides code for hardware operations. These codes interact with each other through the hwobj structure. For the overall driver of MDD + PDD, the serial port driver model is implemented as stream.
The two are integrated to achieve the goal of driving. Ddsi refers to the interface between these two parts. This interface is not subject to mandatory physical/logical relationships, but is manually defined. When a specific hardware is involved, we often need to understand the physical characteristics and control logic of the hardware, and then implement it according to the constraints of ddsi. The key to combining the driver model described here is the use and implementation of the structure pointer hwobj. In actual driver applications, you only need to implement a series of functions related to hwobj, instead of fully developing them from the driver top layer. As a common driver model, the serial port driver model is often used in WindowsCE to implement serial port/infrared/USB client. The full-featured serial port is defined in the driver model. In addition to common Tx and Rx leads, all functional pins such as DTR and RTS are supported, this enables the serial drive designed with this model to support traffic control and the ability to drive modem and other devices.
As a matter of fact, if necessary, it would be possible to integrate the drive design (leave aside the division of the PDD-MDD, there is no need for ddsi ). That is, the existing driver architecture is not used for implementation. Considering that the use frequency and execution efficiency of the serial driver are not very demanding, it is not necessary to discard the driver architecture and implement it.
For the driver itself, the functions and Implementation of the serial driver are quite simple, and it is indeed quite comprehensive, the analysis and understanding of this driver is undoubtedly a good example of learning stream drivers.

Code Analysis

Before starting the specific code, let's take a look at some relevant structures. Hwobj is an abstract set of hardware device operations. The annotation after the definition of the structure is slightly different from the actual usage. bandflags specifies the startup time of ist. You can choose to start ISR during initialization or when the device is turned on. the second parameter specifies the specific system interrupt number to intercept. The last parameter is a structure that defines pointers to various behavior functions for hardware operations. MDD uses these functions to access specific PDD operations.
Typedef struct _ hwobj {
Ulong bindflags; // flags controlling MDD behaviour. Se abve.
DWORD dwintid; // interrupt identifier used if thread_at_init or thread_at_open
Phw_vtbl pfunctbl;
} Hwobj, * phwobj;

Hw_vtbl represents a collection of function pointers for specific hardware operations. The structure points to a series of operations, including initialization, opening, closing, receiving, sending, and setting baudrate. The structure is associated with the specific implementation in PDD and the abstract operation in MDD like a bond. The implementation of PDD must follow the function form described in hw_vtbl and construct the corresponding hw_vtbl instance. The driver is written to implement these functions one by one.
Typedef struct _ hw_vtbl {
Pvoid (* hwinit) (ulong identifier, pvoid pmddcontext, phwobj );
Bool (* hwpostinit) (pvoid phead );
Ulong (* hwdeinit) (pvoid phead );
Bool (* hwopen) (pvoid phead );
Ulong (* hwclose) (pvoid phead );
Interrupt_type (* hwgetintrtype) (pvoid phead );
Ulong (* hwrxintrhandler) (pvoid phead, puchar pTARGET, Pulong pbytes );
Void (* hwtxintrhandler) (pvoid phead, puchar psrc, Pulong pbytes );
Void (* hwmodemintrhandler) (pvoid phead );
Void (* hwlineintrhandler) (pvoid phead );
Ulong (* hwgetrxbuffersize) (pvoid phead );
Bool (* hwpoweroff) (pvoid phead );
Bool (* hwpoweron) (pvoid phead );
Void (* hwcleardtr) (pvoid phead );
Void (* hwsetdtr) (pvoid phead );
Void (* hwclearrts) (pvoid phead );
Void (* hwsetrts) (pvoid phead );
Bool (* hwenableir) (pvoid phead, ulong baudrate );
Bool (* hwdisableir) (pvoid phead );
Void (* hwclearbreak) (pvoid phead );
Void (* hwsetbreak) (pvoid phead );
Bool (* hwxmitcomchar) (pvoid phead, uchar comchar );
Ulong (* hwgetstatus) (pvoid phead, lpcomstat lpstat );
Void (* hwreset) (pvoid phead );
Void (* hwgetmodemstatus) (pvoid phead, Pulong pmodemstatus );
Void (* hwgetcomatrix roperties) (pvoid phead, lpcomatrix drop pcomatrix drop );
Void (* hwpurgecomm) (pvoid phead, DWORD fdwaction );
Bool (* hwsetdcb) (pvoid phead, lpdcb pdcb );
Bool (* hwsetcommtimeouts) (pvoid phead, lpcommtimeouts lpcommto );
Bool (* hwioctl) (pvoid phead, DWORD dwcode, pbyte pbufin, DWORD dwlenin,
Pbyte pbufout, DWORD dwlenout, pdword pdwactualout );
} Hw_vtbl, * phw_vtbl; After explaining the above two structures, let's look at the specific code to ensure a clear understanding of the system architecture, we separate the MDD code from the PDD code for analysis.

MDD Section

Because the serial port driver is directly called by device.exe, The MDD part is provided by the complete stream interface. It also has the function implementation required by the stream-based driver, including com_init and com_deinit.
, Com_open, com_close, com_read, com_write, com_seek, com_powerup, com_powerdown, and com_iocontrol. Because the information sent/received by the serial port cannot be located, but is simply transmitted, com_seek is implemented only in form.

Com_init
Com_init is the initialization function of the driver. It is called first after the driver is loaded in the Device Manager to initialize required variables, hardware devices, and other resources. This process is allocated to represent the data structure of the hardware instance of the device, and the hardware is initialized through the Hardware Abstraction interface hwinit. At the same time, this function will call interruptinitialize to create events for receiving logical interruptions in the kernel and initialize the critical section. This function also needs to obtain the physical address of the hardware buffer and obtain the buffer size (the minimum size of the buffer is 2 K ). Finally, it sets up a buffer as the receiving intermediary. Let's take a look at the implementation process of this function.
Two important variables are defined in the function. Pserialhead and phwhead. The former is used to describe the status of the corresponding serial port, and the latter is the data abstraction of the corresponding hardware. First, allocate space for the pserialhead, initialize data such as the linked list and critical section, and create events for receiving and sending interruptions at the same time. Then, copy the previous registration item value from the registration table (because device.exe calls the Driver Based on the registry key value, the current key registry key refers to the registration item under the same root as the preceding key value ). After obtaining the specific values under devicearrayindex and priority256, you can call getserialobject (implemented in PDD) to obtain the specific hwobj object and call the hardware initialization function through this object. (Because the hardware has been initialized here, com_deinit must be called to complete subsequent responses .) Because the hardware initialization (the actual driver initialization Code) has been executed, only the allocation and initialization buffering work needs to be done. Therefore, hwgetrxbuffersize (PDD Code) is called to obtain the buffer size set in PDD and allocate the buffer according to the returned value. Finally, if bindflags is set to thread_at_init, call startdispatchthread to start the distribution thread (actual ist ). In this way, the system initialization is completed.

Com_deinit
This event is started when the driver is called detached and used as the opposite operation as com_init. This process will roughly release the resources used in the driver and stop the operations such as the threads created during the process. Specifically, it is roughly to stop all ist in MDD, and to release system resources such as memory resources and critical zones. At the same time, you also need to call hwdeinit to release the system resources used in PDD.

Com_open
Com_oepn is called after createfile to open the device in read/write mode, initialize the required space/resources, and create corresponding instances to prepare for subsequent operations. The code here is relatively easy. Here is a brief introduction. Since it is initialization, it is inevitable to check the parameters. First, check whether the phead structure returned through com_init is valid. Although there is no explicit parameter passing between the two functions, this parameter is passed inside the Device Manager.
Check whether the open mode in the Open Handle passed by the file system is valid. This parameter is generated by the application and directly transmitted to the driver through the file system. The initialization starts. The corresponding hw_open_info object will be created here. The following is the definition of the structure.
Typedef struct _ hw_open_info {
Phw_indep_info pserialhead; // @ field pointer back to our hw_indep_info
DWORD accesscode; // @ field what permissions was this opened
DWORD merge mode; // @ field what share mode was this opened
DWORD structusers; // @ field count of threads currently using struct.
Comm_events commevents; // @ field contains all in .... Handling
List_entry lList; // @ field linked list of open_infos
} Hw_open_info, * pH
The first parameter in the structure points to the hw_indep_info structure we mentioned earlier. The second parameter is the operation permission code, that is, the read/write permission. The third parameter is the shared mode to determine whether exclusive mode is supported. Both parameters correspond to the content of the file system. The commevent corresponds to the event of this instance. Because the driver architecture supports the existence of multiple open operation instances, a linked list is maintained here to connect these structures. Here, because ist can be started in com_init and com_open, there is also content for the processor to start ist. After preparing the hw_open_info structure, you can call hwopen (PDD) to perform the open operation required by PDD. After the open operation is complete, hwpurgecomm (PDD) is called to process (cancel or wait) tasks that are still in the communication status. Then reset the software FIFO to complete the com_open action.
In fact, this is mainly to process the required data structure, and the specific hardware operations are left for PDD. What MDD maintains is only a disruptive code. After the open operation is complete, the driver enters the working state.

Com_close
Com_close is the operation corresponding to com_open. The purpose of this period is to release the system resources used by com_open. In addition, if a corresponding ist is created during com_open, the thread needs to be stopped and the hw_open_info is finally dechained. In this way, the driving status can be restored. Of course, during this period, a write operation was also performed to avoid thread competition, making the code not so simple.

Startdispatchthread/stopdispatchthread
These two functions are not the standard interfaces required by stream, but they are the means of ist startup and shutdown required to interrupt the service program.
The startdispatchthread function is used to start ist. The main task is to call interruptinitialize to associate the system interruption with the corresponding event. Start serialdispatchthread as ist. Call the interruptdone function, which calls oeminterruptdone in oal to complete the interrupt response.
Stopdispatchthread is used for operations opposite to startdispatchthread. The process of stopping is relatively complicated. The function first sets the priority of the current thread to be the same as that of the distribution thread, so that the action of stopping the thread is no faster than the action of releasing the memory to avoid errors. The stop action is performed by the thread. The specific method is to submit the killrxthread to Request Scheduling through sleep and wait until the IST stops. At this time, because the IST has been stopped, interruptdisable is called at the end of the program to block the interruption.


Serialdispatchthread/serialeventhandler
Serialdispatchthread/serialeventhandler is the interrupt distribution program (that is, the IST) driven by the serial port ). The entire ist is divided into two parts: the cyclic subject and the event handler. The content of the cyclic subject serialdispatchthread is relatively simple. It waits for serial events and calls serialeventhandler to process specific interruptions until pserialhead-> killrxthread is set and exits. Serialeventhandler is the specific implementation of interrupt processing. The program runs after a serial event is obtained to further judge the interrupt and perform corresponding processing.
The following two structures are used to analyze the acceptance and sending interruption services. Let's take a look at the structure of rx_buffer_info.
Typedef struct _ rx_buffer_info {
Ulong read;/* @ field current read index .*/
Ulong write;/* @ field current write index .*/
Ulong length;/* @ Field Length of buffer */
Bool dataavail;/* @ field bool reflecting existence of data .*/
Puchar rxcharbuffer;/* @ field start of buffer */
Critical_section Cs;/* @ field critical section */
} Rx_buffer_info, * prx_buffer_info;
This structure is used because a buffer is maintained inside the driver for buffering between the driver and the application.
We can see that there is a FIFO buffer in the hardware, which ensures the driver's data reception. However, because the application may not be able to ensure that the data is removed in time after the driver obtains the data, therefore, another buffer is maintained in the driver. The read member in the rx_buffer_fifo structure indicates the position of the FIFO when the MDD is used to retrieve data. The bit mark written by PDD to the software is called write, dataavail is used to indicate whether the data in the buffer is valid. Rxcharbuffer is a pointer to the software FIFO. When the data is received, the write flag is incremented, and the program increments the read when it returns the data to the driver. In this way, the Read and Write members can be used to maintain the FIFO. With this basic idea, let's look at how to implement the RX interrupt service. This will also involve the flow control components.
Receiving branch: calculates the remaining space of the software buffer at the beginning of the receiving branch. If there is any remaining space, call hwrxintrhandler (pdda implementation) to obtain the data of the remaining space from the hardware buffer, if no space is available, a 16-byte temporary buffer is created to read data into this region, in fact, this buffer zone will not be read at the end, so all the data is lost. This naturally requires statistics on data loss caused by hardware/software buffering (delayed reception ). The next step is the so-called xflow process. The so-called xflow is the software flow control we mentioned above. That is to say, the software method is used to coordinate the sending and receiving ends to ensure the complete receipt of data. When the xoff/Xon mark is received, because the mark itself is not data but a control mark, it is necessary to say that all the subsequent data is placed first to overwrite the Xon/xoff position. You also need to set the control labels in the DCB structure based on the specific status of the indicators to control the data sending and receiving process. If it is the Xon flag, you also need to resume the sending process after processing the receipt process. The received action changes the position of the write mark. You need to recalculate the mark here. In the process of hardware flow control, the driver model starts and stops sending and receiving Based on 75% of the buffer. The available hardware connections can be DTR, it can also be the same (the same pattern is only different from the line). The operation here is very simple. It only completes the hardware flow control operation by clearing the mark by calculating the storage status of the buffer. Because ist and other parts are executed synchronously during this process, a security check may be required if xflow is used. The receiving process ends.
Sending branch: Let's take a look at the tx_buffer_info structure. It seems that this structure maintains a buffer similar to the Tx buffer, but in fact this buffer area does not exist independently, because the storage area of the data to be sent can be directly used as the sending buffer, there is no need for this buffer to exist independently. Because the data area of other processes is used, the permission Control item is added here to break through the access restrictions between processes.
Typedef struct _ tx_buffer_info {
DWORD permissions;/* @ field current permissions */
Ulong read;/* @ field current read index .*/
Ulong length;/* @ Field Length of buffer */
Puchar txcharbuffer;/* @ field start of buffer */
Critical_section Cs;/* @ field critical section */
} Tx_buffer_info, * ptx_buffer_info;
Next let's take a look at the specific content of the Code. First, check opencnt, that is, whether the device is enabled. If the session is closed, it is unnecessary to send data again and reset the flag of the buffer. The entire process is relatively simple. You can set the RTS or check the xflow when you need traffic control and then send the data to the hardware buffer. if no data needs to be sent, simply clear the interrupt mark and send the end event. As for the setprocpermissions setting, the purpose is to obtain the means to access the data space of other threads.
The so-called modem and line are all handled by PDD. We will discuss it later. After all of these processes are completed, if you have previously processed the receipt, the program will receive the received message (available data for receiving. A evaluateeventflag function is also followed up later. This function is used to generate the standard communication events ev_rxflag, and because the driver itself supports the mult-open mode, therefore, you need to send the event to all instances. There are some operations in the interlock and critical section during the IST process, because it does not affect the process, I did not mention the contents of synchronization here. This is roughly the case in the analysis of service interruption. The logic is not involved in the subsequent PDD section.

Com_read
Com_read is the operation to obtain the data received by the serial port. In the previous ist, the operation to modify the read Mark on the RX buffer is not seen, that is, this operation is done here. This function has three parameters. The first parameter is exchanged from the above com_open through the Device Manager. The last two parameters are the same as those used by the file system. The other two parameters are buffer pointers, the other is the length. The beginning of the code is still a routine parameter check, including access permissions, opencnt and so on. Then calculate the timeout value. If the read time-out operation is set, the system returns the result after the timeout value, regardless of whether the data has been read for a sufficient length. The next step is to simply read the software buffer. The read operation is completed in rx_cs. The following are the main exceptions of the processor. During the reading process, the device is disabled/unread and timed out. At last, what needs to be processed in the read process is only the cost of flow control. The first is the software stream. If the buffer status is from higher than the sub-point to below the sub-point, the Xon mark is issued to start sending at the sending end. However, the hardware stream is similar to the software stream in either the RTS or DTR. It is also determined by a point (50%) to send a signal to start the sending end, only the specific measures used here are different. These hardware signals are all sent by PDD, including hwsetrts and hwsetdtr (either ). Now the read process is complete.

Com_write
Com_write is the operation corresponding to com_read. The transmitted parameters are similar in the form of different data flows. At the beginning of the program, it is also a parameter check, with the content consistent with com_read. After the data check is complete, enter the critical section (to ensure the exclusive operation under multiple threads) and set the destination address and length to TX buffer. After the event is sent, call dotxdata to start sending. The purpose of enabling sending is to obtain the hardware interruption and maintain the sending process. Here, dotxdatais executed in two states. In the process that passes the execution of com_write, it is executed in the thread space created by device.exe. However, the process space of the IST itself exists during the active startup of the system interrupt event, in this way, the permission code set before calling dotxdata in com_write (obtained by getcurrentpermissions) the txbufferinfo can be passed to the ist so that the interrupt process has the access buffer permission (combined with the process described above ). After sending the submitted interrupt processing, the sending process is completed after pserialhead-> htransmitevent is set or an exception or timeout. Similar to com_read, some exceptions need to be handled. Of course, if you use hardware flow control, you need to clear the sending request signal here, after processing these statuses, send the ev_txempty event to notify all open handles that the process is completed.

Com_powerup/com_powerdown
Both functions are triggered by Ce power events. MDD does not process these two functions and only transmits them to PDD.

Com_iocontrol
This function is used to send commands to devices. Since the Code itself does not have any flow or logic, it is all implemented independently. The following describes these command words and their implementations in the form of a list.

Command
Note

Ioctl_psl_policy
It is generated when the process that calls the driver exits. It is not a dedicated Io command of the serial driver. The processexiting function is called for processing. The content of this function is shown later.

Ioctl_serial_set_break_on
Interrupt (pause) The current sending or receiving of serial. The specific implementation is in PDD.

Ioctl_serial_set_break_off
Recover from the interrupted (paused) status. The specific implementation is in PDD.

Ioctl_serial_set_dtr
Increase the DTr lead height. (Directly call the PDD implementation)

Ioctl_serial_clr_dtr
Lower the DTr lead. (Directly call the PDD implementation)

Ioctl_serial_set_rts
Increase the RTS lead. (Directly call the PDD implementation)

Ioctl_serial_clr_rts
Lower the RTS lead. (Directly call the PDD implementation)

Ioctl_serial_set_xoff
Xflow Control)

Ioctl_serial_set_xon
Xflow Control)

Ioctl_serial_get_wait_mask
Obtains the current event object.

Ioctl_serial_set_wait_mask
Setting event objects is relatively troublesome. You need to set the current event object mask to all open instances, which is similar to the previous evaluateeventflag process.

Ioctl_serial_wait_on_mask
Wait for the same event as the provided event to occur, and the implemented entity is waitcommevent, which will be discussed later.

Ioctl_serial_get_commstatus
Clear the exception and return the current status (implemented by PDD)

Ioctl_serial_get_modemstatus
Obtain the modem status (implemented by PDD)

Ioctl_serial_get_properties
Get communication ************************ (implemented by PDD)

Ioctl_serial_set_timeouts
Set the timeout time (including PDD implementation)

Ioctl_serial_get_timeouts
Get timeout

Ioctl_serial_purge
Clear Data in the specified sending or receiving buffer (including PDD implementation)

Ioctl_serial_set_queue_size
Unknown. Please let us know if you know

Ioctl_serial_immediate_char
For the extended feature, set a flag number before sending data

Ioctl_serial_get_dcb
Obtain the DCB Data Structure

Ioctl_serial_set_dcb
Set the DCB Data Structure

Ioctl_serial_enable_ir
Start the infrared mode (implemented by PDD)

Ioctl_serial_disable_ir
Disable the infrared mode (implemented by PDD)

The main functions of MDD have been introduced here. The following functions are used in deviceiocontrol. Here, let's take a look:
Processexiting
This function is called during the execution of the ioctl_psl_notify command. The previous scenario is that the driver process is canceled. Here, it is used to clear all threads in the session. To kill the process directly.
Waitcommevent
In fact, this function is the implementation of serialapi waitcommevent in the driver. Its function is to block a fixed serial port announcement (event message) in the thread. In specific implementation, waitforsingleobject is used to implement blocking. Before blocking occurs, the function applies to a cyclic subject. First, you can check whether there are existing notifications that match the pending notifications. If not, wait for the next event to occur and check again when the event occurs. So that the loop is blocked.
Applydcb
The DCB data structure is used to describe the serial port baud rate, traffic control, and parity. This function is used to set the DCB data structure to the driver's internal and hardware. A large number of PDD operations are used to complete hardware settings.

Summary:
In terms of driver implementation, apart from the so-called multi-open processing, the MDD of the serial port is nothing special, it is easy to understand the code after understanding the hardware behavior and application software behavior.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.