當前位置:首頁 » 操作系統 » linux虛擬串口

linux虛擬串口

發布時間: 2022-03-31 13:46:41

1. 求教,linux下網口虛擬串口驅動程序

開發虛擬串口驅動程序

虛擬串口就是當本地並沒有對應的串口硬體設備,而為應用層提供串口設備一樣的系統調用介面,以兼容原本使用本地串口的應用軟體的「虛」設備。本文作者給出了一種在Windows平台上實現虛擬串口的方法,由此實現的「串口」具有真實串口完全相同的系統調用介面。
在很多應用中需要用到虛擬串口,如在Modem卡出現之前,已經有了接在計算機串口上的外部Modem,而且各種拔號程序也是通過串口與外部Modem通信的。為了讓已有的拔號程序不做修改,像使用外部Modem一樣使用內置卡,就需要內置卡的驅動程序虛擬一個串口設備。又如當前工業界使用的一些串口伺服器,往往有8個或16個甚至更多的串口,以連接多個串口設備,再通過一個網卡直接連入乙太網。與它在同一網路上的計算機就通過乙太網與串口伺服器上掛接的串口設備通信。為了讓計算機中原來使用本地串口的軟體兼容,就需要在計算機上提供虛擬串口驅動。
虛擬串口的設計關鍵在於,該「串口」實現後必須具有與真實串口完全相同的系統調用介面。要做到這點,從已有的串口設備驅動程序上做修改是最佳捷徑。下文就介紹以Windows NT上的串口驅動程序為基礎,開發可運行於Windows NT、Windows 2000、Windows XP的各個版本虛擬串口驅動程序。
串口驅動中使用的幾個鏈表
由於串口是雙工設備,在一個讀請求發出來還沒有完成之前,同時可以發出寫請求,加上在驅動程序層所有I/O請求都要求非同步完成,即前一個請求尚沒有完成,下一個相同的請求可能又來了。為此,串口驅動程序需要使用多個雙向鏈表數據結構來處理各種IRP(I/O Request Packet,I/O請求包)。當收到一個IRP,先判斷是否可立即完成,可以馬上處理並返回,如果不允許則將IRP插在相應鏈表尾,在適當的時候如設備有空閑時處理,這時往往會產生一個硬體中斷,激發DPC(Deferred Procere Call,暫緩過程調用)過程,由DPC處理函數逐個從鏈表頭取出IRP並試著完成它。串口驅動中有以下幾個鏈表和DPC(在serial.h中有定義):
ReadQueue 和 CompleteReadDpc
用於保存Read IRP的鏈表和用於調度的DPC,與DPC對應的處理函數是SerialCompleteRead,它在read.c文件中,該函數的主要任務就是從ReadQueue中提取下一個IRP,並試著完成它。
WriteQueue 和 CompleteWriteDpc
用於保存Write IRP的鏈表和對應的DPC,與DPC對應的函數是SeriaCompleteWrite,它的實現在write.c中,該函數負責從WriteQueue中提取IRP,並試著完成它。
MaskQueue 和 CommWaitDpc
這一對鏈表用於處理Windows串口驅動的一個特性:事件驅動機制。它允許應用程序預設一個事件標志,而後等待與標志對應事件發生。DPC所調用的函數是SerialCompleteWait,它實現在Waitmask.c文件中,該函數也是試著從MaskQueue中提取IRP並完成它。
PurgeQueue
該鏈表與前面幾個稍有不同,它沒有與之相對應的DPC機制,而是在每次收到Purge請求時從PurgeQueue中逐個提取IRP並試著完成,因某種原因不能完成時則插入鏈表。相應的函數是purge.c文件中的SerialStartPurge。
以上機制是串口驅動程序的重要實現方法,在虛擬串口驅動中需要保留,但不同的是,硬體串口驅動中是ISR(中斷服務程序)根據收、發或MODEM中斷來激發相應的DPC,而在虛擬串口驅動中將因實際情況不同會有不同的激發機制。
DriverEntry的實現
DriverEntry是驅動程序的入口函數,相當於應用程序C語言中的main函數,開發一個虛擬串口驅動首先要修改的就是它。它的函數實體在initunlo.c文件中。只是在虛擬串口驅動中由於不與具體的硬體打交道,就不存在硬體資源分析、硬體初始化、判斷其工作狀態等處理,只需要為虛擬串建立設備對象、符號鏈接和初始化數據結構。一個典型函數實現大體如下:
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
/*填寫DriverObject->MajorFunction[]數組*/
/*建立設備對象*/
/*初始化SERIAL_DEVCIE_EXETENSION數據結構*/
Status = IoCreateDevice(DriverObject, sizeof(SERIAL_DEVICE_EXTENSION), &uniNameString, FILE_DEVICE_SERIAL_PORT, 0,TRUE,&deviceObject);
//初始化所有鏈表
InitializeListHead(&extension->ReadQueue);
InitializeListHead(…);
…;
//初始化所有DPC
KeInitializeDpc(&extension->CompleteReadDpc,SerailCompleteRead,extension);
KeInitializeDpc(…);
/*建立符號鏈接*/
SerialSetupExternalNaming(extension);
return Status;
}
SerialRead和SerialCompleteRead的實現
函數SerailRead和SerialCompleteRead決定了對Read IRP的響應策略,它們都存於read.c中。以串口伺服器要用的虛擬串口為例,當串口伺服器收到來自外部數據時將通過網路發至計算機,計算機則產生相應的網路中斷並進行協議數據處理。網路接收線程緩存新收到的數據並激活CompleteReadDpc,從而SerialCompleteReadIrp得到調用,它再調用CompleteReadIrp對每個IRP進行處理。它們的實現大體如下:
NTSTATUS SerialRead(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
/*此處略去變數聲明和初始化*/
/*提取IRP中相關的數據*/
stack = IoGetCurrentIrpStackLocation(Irp);
ReadLen = stack->Parameters.Read.Length;
/*先看本地緩沖有數據否?有的話先讀取*/
if(Extension->InCounter > 0 )
{ //注意這里要加鎖,以防數據訪問沖突
KeAcquireSpinLock(&Extension->
ReadBufferLock,&lIrql);
FirstRead = (ReadLen>Extension->
InCounter)? Extension->InCounter: ReadLen;
RtlCopyMemory(Irp->AssociatedIrp.
SystemBuffer,Extension->pInBuffer,FirstRead);
Extension->InCounter -= FirstRead;
ReadLen -= FirstRead;
KeReleaseSpinLock(&Extension->
ReadBufferLock,lIrql);//釋放鎖
}
/*是否已讀到足夠數據?是的話則完成該IRP*/
if( 0 == ReadLen)
{
status=STATUS_SUCCESS;
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = FirstRead;
IoCompleteRequest(Irp,0);
return status;
}
/*沒有則將IRP插入隊列中,通過網路向串口伺服器發出讀數據請求*/
IoMarkIrpPending(Irp);
InsertWaitList(Extension->ReadQueue,Irp);
status = TdiSendAsync(Extension->ComChannel,pAckPacket,PacketLen(pAckPacket),(PVOID)ReadAckComplete,Irp);
/*返回PENDING,表示該IRP尚沒有完成*/
return STATUS_PENDING;
}
Void CompleteReadIrp(IN PSERIAL_DEVICE_EXTENSION extension,IN PIRP Irp,IN PUCHAR pInData,IN ULONG Length )
{
/*此處略去變數聲明和初始化*/
/*讀取新數據*/
ReadLen = (ReadLen > Length)? Length : ReadLen;
if(ReadLen != 0)
{
RtlCopyMemory(pReadAsync->
pReadBuffer,pInData,ReadLen);
pReadAsync->pReadBuffer += ReadLen;
pReadAsync->ReadAlready += ReadLen;
extension->PerfStats.ReceivedCount +=
ReadLen;
}
else
{
/*因為串口伺服器端只有在已經有了相應的數據或超過時間(此時,Length=0)才會發來應答並激活本DPC過程,所以此時已經超時,為了便於結束本IRP,這里有意改變TotalNeedRead,造成接收完畢的假象*/
pReadAsync->TotalNeedRead =
pReadAsync->ReadAlready;
}
if(pReadAsync->TotalNeedRead == pReadAsync->ReadAlready)
{
/*該IRP是否已經接收完畢,是的話則結束該
IRP*/
EndReadIrp(Irp);
/*從ReadQueue中取下一個IRP*/
}
/*本IRP沒有完成也沒有超時,則繼續等待本DPC下次被激活,注意此時要判斷IRP是否被要求取消*/
}
SerialWrite和SerailCompleteWrite的實現
SerialWrite和SerailCompleteWrite決定了Write IRP的實現。在SerialWrite中調用了網路發送函數TdiSendAsync,當該發送完成後將激活CompleteWriteDpc,調度SerialCompleteWrite函數,而它主要就是取出當前的WriteIRP,設置已經發送的數據數量,調用CompleteWriteIrp做該IRP的進一步處理。它們大體如下:
NTSTATUS SerialWrite(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
/*此處略去變數聲明和初始化*/
/*從IRP中提取有關數據*/
stack=IoGetCurrentIrpStackLocation(Irp);
SendLen = stack->Parameters.Write.Length;
/*為網路發送和非同步操作分配緩沖,在CompleteWrite中全部數據發送完後釋放*/
pWriteAsync = ExAllocatePool(NonPagedPool,
SendLen+PACKET_HEADER_LEN+sizeof(WRITE_ASYNC));
if(pWriteAsync == NULL)
{
//錯誤處理
}
//保存非同步數據

//設置網路發送數據包
BuildDataPacket(pPacket,WRITE,(USHORT)SendLen,pWriteAsync->pWriteBuffer);
/*先將IRP暫時阻塞並插入隊列,在CompleteWrite中完成*/
IoMarkIrpPending(Irp);
InsertWaitList(extension->WriteQueue, Irp);
/*將寫請求和相關數據通過網路發向串口伺服器,由它負責將數據傳到具體串口設備*/
status = TdiSendAsync(Extension->ComChannel,pPacket,PacketLen(pPacket),(PVOID)CompleteWriteIrp,Irp);
//統計數據累加
Extension->PerfStats.TransmittedCount += SendLen;
return STATUS_PENDING;
}

NTSTATUS CompleteWriteIrp(IN PDEVICE_OBJECT deviceobject,IN PIRP pIrp,IN PVOID context)
{
/*此處略去變數聲明和初始化*/
SendLen=pWriteAsync->TotalNeedWrite - pWriteAsync->WroteAlready;
if(SendLen == 0)//全部數據發送完畢
{
EndWaitWriteIrp(pWriteIrp,STATUS_SUCCESS,
pWriteAsync->WroteAlready,pWriteAsync);
//從WriteQueue中取下一個IRP;
}
else //發送剩餘數據
{
if(pWriteIrp->Cancel)
{
//IRP被要求取消,完成WriteIrp
EndWaitWriteIrp(pWriteIrp,STATUS_CANCELLED,
pWriteAsync->WroteAlready,pWriteAsync);
return STATUS_CANCELED;
}
else
{
//再次設置網路數據包並發送
BuildDataPacket(…);
status = TdiSendAsync(…);
//統計數據累加
Extension->PerfStats.TransmittedCount +=
SendLen;
return STATUS_MORE_PROCESSING_REQUIRED;
}
}
}
其他幾個介面函數的實現
除Read/Write外,SerialUnload、SerialCreateOpen、 SerialClose、SerialCleanup、SerailFlush等調用介面是硬體相關性比較弱的介面函數,基本不要修改,直接刪除原來操作硬體的部分即可。復雜一點就是SerialIoControl,該介面函數包含有大量設置、讀取串口硬體狀態的處理,可建立一個本地數據結構隨時保存虛擬串口的當前硬體狀態。同時為了保證串口伺服器端的真實串口狀態和上層軟體要求的一致,需要將所有設置請求通過網路發送到伺服器端,由它負責改變真實硬體的狀態。

2. 如何在 Linux 下根據 IP及埠 虛擬成串口

虛擬機中的串口連接可以採用兩種方法。一種是指定虛擬機的串口連接到實際的COM上,例如開發機連接到COM1,目標機連接到COM2,然後把兩個串口通過串口線相連接。另一種更為簡便的方法是:在較高一些版本的VMware中都支持把串口映射到命名管道,把兩個虛擬機的串口映射到同一個命名管道。例如,在兩個虛擬機中都選定同一個命名管道 \\.\pipe\com_1,指定target機的COM口為server端,並選擇"The other end is a virtual machine"屬性;指定development機的COM口端為client端,同樣指定COM口的"The other end is a virtual machine"屬性。對於IO mode屬性,在target上選中"Yield CPU on poll"復選擇框,development機不選。

3. linux下如何使用虛擬串口的usb設備

usb轉串口設備需要單獨安裝驅動的,如果沒有驅動,當然無法識別了

4. 如何查看linux下串口是否可用串口名稱等

1、查看串口是否可用,可以對串口發送數據比如對com1口,echo lyjie126 > /dev/ttyS0

2、查看串口名稱使用 ls -l /dev/ttyS* 一般情況下串口的名稱全部在dev下面,如果你沒有外插串口卡的話默認是dev下的ttyS* ,一般ttyS0對應com1,ttyS1對應com2,當然也不一定是必然的;

3、查看串口驅動:cat /proc/tty/drivers/serial

4、查看串口設備:dmesg | grep ttyS*

(4)linux虛擬串口擴展閱讀

介面劃分標准

同步串列介面(英文:SynchronousSerialInterface,SSI)是一種常用的工業用通信介面。。

非同步串列是指UART(Universal Asynchronous Receiver/Transmitter),通用非同步接收/發送。UART是一個並行輸入成為串列輸出的晶元,通常集成在主板上。UART包含TTL電平的串口和RS232電平的串口。 TTL電平是3.3V的,而RS232是負邏輯電平,它定義+5~+12V為低電平,而-12~-5V為高電平,MDS2710、MDS SD4、EL805等是RS232介面,EL806有TTL介面。

串列介面按電氣標准及協議來分包括RS-232-C、RS-422、RS485等。RS-232-C、RS-422與RS-485標准只對介面的電氣特性做出規定,不涉及接插件、電纜或協議。

5. linux下usb設備如何虛擬為串口設備

亞嵌教育 技術論壇 你可以去找找答案

6. 一台筆記本上裝了個虛擬的linux,在linux下運行了串口通信的程序,不知需要什麼設備調試這個串口程序

我知道你的意思,你是裝了虛擬機,所以虛擬機里有關於你這個系統的設備配置的,比如內存呀,硬碟呀,你再添加一個串口設備就好了,然後你在你的windows下用串口調試工具,在虛擬機的linux下運行你的程序,應該就可以通信了。

7. ARM和linux虛擬機串口通信,ARM端打不開串口設備。

查一下板子上的串口設備有沒有:
grep tty /proc/devices
如果有ttyS設備,再看/dev/有沒有ttySx,如沒有就建立一個:
mknod /dev/ttyS0 c 4 64

8. 如何設置linux虛擬機啟動時的串口波特率

用命令minicom -s 可以進到串口的設置界面 一般串口的Serial Device 值是填/dev/ttyS0 然後設置一下Bps/Par/Bits 保存,根據提示登陸串口即可

9. Linux藍牙怎樣虛擬成串口

沒插好

10. VMware上的Linux虛擬機讀串口數據

你需要去買個usb轉232口的線,然後裝上驅動,再就在虛擬機裡面配置好串口,剩下的就是正常寫串口的程序而已了

熱點內容
db2建表空間時怎麼配置頁大小 發布:2024-11-15 17:58:45 瀏覽:424
我的世界好玩地鐵伺服器 發布:2024-11-15 17:48:54 瀏覽:359
1710小游戲伺服器ip 發布:2024-11-15 17:48:01 瀏覽:663
狂三腳本 發布:2024-11-15 17:31:38 瀏覽:872
附近存儲櫃 發布:2024-11-15 17:15:17 瀏覽:452
王選解決漢字存儲問題 發布:2024-11-15 17:15:11 瀏覽:660
球球大作戰安卓為什麼不能玩哪些模式 發布:2024-11-15 17:14:26 瀏覽:996
存儲器講課 發布:2024-11-15 17:14:12 瀏覽:196
安卓充電頭怎麼稱呼 發布:2024-11-15 17:11:17 瀏覽:446
獵人手游源碼 發布:2024-11-15 17:09:28 瀏覽:433