以下是一个驱动层 + 用户态的交互示例,覆盖“超时设置+设备状态查询+数据读写”全流程,包含驱动代码、用户态头文件、用户态调用代码。
一、整体架构说明
| 层级 | 核心文件/功能 |
|---|---|
| 驱动层 | 实现IRP_MJ_DEVICE_CONTROL处理逻辑,响应自定义IOCTL(设置超时、查状态、读写数据) |
| 接口层 | ioapist.h:封装IOCTL、结构体、用户态API声明 |
| 用户态层 | 调用ioapist.h封装的API,完成设备打开、参数下发、数据交互、设备关闭 |
二、步骤1:定义公共接口头文件ioapist.h
ioapist.h 并非 Windows 系统原生公开的头文件(不属于 MSDN/Windows SDK 标准头文件),而是行业 / 厂商自定义的接口头文件,核心用于封装设备 I/O 操作的 API 集合(尤其是通过DeviceIoControl实现的设备控制、数据交互逻辑),常见于硬件驱动开发、工业控制、嵌入式 Windows 设备通信等场景。
该文件是驱动和用户态的“协议约定”,需保证两端结构体、IOCTL完全一致。
#ifndefIOAPIST_H#defineIOAPIST_H#ifdef__cplusplusextern"C"{#endif/************************ 1. 基础常量定义 ************************/// 自定义设备类型(避开Windows系统预留值,范围0x8000-0xFFFF)#defineFILE_DEVICE_CUSTOM_DEV0x8000// 缓冲区方式(驱动与用户态数据交互方式,这里用缓冲式,最通用)#defineMETHOD_CUSTOMMETHOD_BUFFERED// 访问权限#defineFILE_CUSTOM_ACCESSFILE_ANY_ACCESS// 封装CTL_CODE宏,生成唯一IOCTL控制码#defineCUSTOM_CTL_CODE(code)\CTL_CODE(FILE_DEVICE_CUSTOM_DEV,code,METHOD_CUSTOM,FILE_CUSTOM_ACCESS)/************************ 2. IOCTL控制码定义 ************************/#defineIOCTL_SET_TIMEOUTCUSTOM_CTL_CODE(0x0001)// 设置超时#defineIOCTL_GET_DEVICE_STATUSCUSTOM_CTL_CODE(0x0002)// 获取设备状态#defineIOCTL_WRITE_DATACUSTOM_CTL_CODE(0x0003)// 写数据到设备#defineIOCTL_READ_DATACUSTOM_CTL_CODE(0x0004)// 从设备读数据/************************ 3. 数据交互结构体(驱动/用户态一致) ************************/// 超时设置结构体(对应IOCTL_SET_TIMEOUT)typedefstruct_DEV_TIMEOUT{DWORD dwReadTimeout;// 读超时(毫秒)DWORD dwWriteTimeout;// 写超时(毫秒)DWORD dwCtrlTimeout;// 控制指令超时(毫秒)}DEV_TIMEOUT,*PDEV_TIMEOUT;// 设备状态结构体(对应IOCTL_GET_DEVICE_STATUS)typedefstruct_DEV_STATUS{BOOL bOnline;// 设备是否在线(TRUE/FALSE)DWORD dwErrorCount;// 累计错误数DWORD dwBufferSize;// 设备缓存区大小DWORD dwReserved;// 预留字段(保证结构体对齐)}DEV_STATUS,*PDEV_STATUS;// 数据读写结构体(对应IOCTL_READ/WRITE_DATA)typedefstruct_DEV_DATA{BYTE szBuffer[1024];// 数据缓冲区DWORD dwDataLen;// 有效数据长度(输入/输出)DWORD dwErrorCode;// 操作错误码(输出)}DEV_DATA,*PDEV_DATA;/************************ 4. 辅助常量/枚举 ************************/// 默认设备路径(用户态打开设备用)#defineDEFAULT_DEVICE_PATHL"\\\\.\\CustomDevice"// 超时默认值#defineDEFAULT_READ_TIMEOUT5000// 5秒#defineDEFAULT_WRITE_TIMEOUT3000// 3秒#defineDEFAULT_CTRL_TIMEOUT2000// 2秒// 设备状态枚举(辅助用户态判断)typedefenum{DEV_STATUS_OFFLINE=0,DEV_STATUS_ONLINE=1,DEV_STATUS_ERROR=2}DEV_STATUS_ENUM;/************************ 5. 用户态封装API声明 ************************/// 打开设备(封装CreateFileW)HANDLE __stdcallDevOpen(LPCWSTR lpDevicePath,// 设备路径(如DEFAULT_DEVICE_PATH)DWORD dwDesiredAccess// 访问权限(GENERIC_READ | GENERIC_WRITE));// 关闭设备(封装CloseHandle)VOID __stdcallDevClose(HANDLE hDevice);// 设置设备超时(封装DeviceIoControl + IOCTL_SET_TIMEOUT)BOOL __stdcallDevSetTimeout(HANDLE hDevice,PDEV_TIMEOUT pTimeout);// 获取设备状态(封装DeviceIoControl + IOCTL_GET_DEVICE_STATUS)BOOL __stdcallDevGetStatus(HANDLE hDevice,PDEV_STATUS pStatus);// 写数据到设备(封装DeviceIoControl + IOCTL_WRITE_DATA)BOOL __stdcallDevWriteData(HANDLE hDevice,PDEV_DATA pData);// 从设备读数据(封装DeviceIoControl + IOCTL_READ_DATA)BOOL __stdcallDevReadData(HANDLE hDevice,PDEV_DATA pData);#ifdef__cplusplus}#endif#endif// IOAPIST_H三、步骤2:驱动层实现(内核态,C语言)
驱动基于WDM框架开发,核心实现IRP_MJ_DEVICE_CONTROL回调,处理用户态下发的IOCTL指令。
1. 驱动头文件(CustomDev.h)
#ifndefCUSTOM_DEV_H#defineCUSTOM_DEV_H#include<wdm.h>#include"ioapist.h"// 引入公共接口头文件// 设备扩展结构体(保存设备状态、超时配置等)typedefstruct_DEVICE_EXTENSION{PDEVICE_OBJECT pDeviceObj;// 设备对象指针UNICODE_STRING ustrDeviceName;// 设备名UNICODE_STRING ustrSymLinkName;// 符号链接名// 设备运行状态DEV_TIMEOUT stTimeout;// 超时配置(用户态下发)DEV_STATUS stStatus;// 设备状态BYTE szDevBuffer[1024];// 设备内部缓存区DWORD dwDevBufferLen;// 缓存区有效数据长度}DEVICE_EXTENSION,*PDEVICE_EXTENSION;// 函数声明NTSTATUSDriverUnload(PDRIVER_OBJECT pDriverObj);NTSTATUSDispatchCreateClose(PDEVICE_OBJECT pDeviceObj,PIRP pIrp);NTSTATUSDispatchDeviceControl(PDEVICE_OBJECT pDeviceObj,PIRP pIrp);#endif// CUSTOM_DEV_H2. 驱动实现文件(CustomDev.c)
#include"CustomDev.h"/************************ 1. 驱动入口函数 ************************/NTSTATUSDriverEntry(PDRIVER_OBJECT pDriverObj,PUNICODE_STRING pRegistryPath){NTSTATUS status;PDEVICE_OBJECT pDeviceObj=NULL;PDEVICE_EXTENSION pDevExt=NULL;UNICODE_STRING ustrDeviceName;UNICODE_STRING ustrSymLinkName;// 1. 设置驱动卸载例程pDriverObj->DriverUnload=DriverUnload;// 2. 设置分发例程(处理Create/Close/DeviceControl)pDriverObj->MajorFunction[IRP_MJ_CREATE]=DispatchCreateClose;pDriverObj->MajorFunction[IRP_MJ_CLOSE]=DispatchCreateClose;pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL]=DispatchDeviceControl;// 3. 创建设备对象RtlInitUnicodeString(&ustrDeviceName,L"\\Device\\CustomDevice");status=IoCreateDevice(pDriverObj,// 驱动对象sizeof(DEVICE_EXTENSION),// 设备扩展大小&ustrDeviceName,// 设备名FILE_DEVICE_CUSTOM_DEV,// 设备类型(与ioapist.h一致)0,// 设备特性FALSE,// 非独占&pDeviceObj// 输出设备对象);if(!NT_SUCCESS(status)){DbgPrint("IoCreateDevice failed, status: 0x%X\n",status);returnstatus;}// 4. 初始化设备扩展pDevExt=(PDEVICE_EXTENSION)pDeviceObj->DeviceExtension;pDevExt->pDeviceObj=pDeviceObj;pDevExt->ustrDeviceName=ustrDeviceName;// 初始化默认超时pDevExt->stTimeout.dwReadTimeout=DEFAULT_READ_TIMEOUT;pDevExt->stTimeout.dwWriteTimeout=DEFAULT_WRITE_TIMEOUT;pDevExt->stTimeout.dwCtrlTimeout=DEFAULT_CTRL_TIMEOUT;// 初始化设备状态pDevExt->stStatus.bOnline=TRUE;// 默认在线pDevExt->stStatus.dwErrorCount=0;// 无错误pDevExt->stStatus.dwBufferSize=1024;// 缓存区大小1024pDevExt->dwDevBufferLen=0;// 初始无数据// 5. 创建符号链接(用户态可通过\\.\CustomDevice访问)RtlInitUnicodeString(&ustrSymLinkName,L"\\DosDevices\\CustomDevice");pDevExt->ustrSymLinkName=ustrSymLinkName;status=IoCreateSymbolicLink(&ustrSymLinkName,&ustrDeviceName);if(!NT_SUCCESS(status)){DbgPrint("IoCreateSymbolicLink failed, status: 0x%X\n",status);IoDeleteDevice(pDeviceObj);returnstatus;}DbgPrint("CustomDev Driver Load Success!\n");returnSTATUS_SUCCESS;}/************************ 2. 驱动卸载例程 ************************/NTSTATUSDriverUnload(PDRIVER_OBJECT pDriverObj){PDEVICE_OBJECT pDeviceObj=pDriverObj->DeviceObject;PDEVICE_EXTENSION pDevExt=(PDEVICE_EXTENSION)pDeviceObj->DeviceExtension;// 删除符号链接IoDeleteSymbolicLink(&pDevExt->ustrSymLinkName);// 删除设备对象IoDeleteDevice(pDeviceObj);DbgPrint("CustomDev Driver Unload Success!\n");returnSTATUS_SUCCESS;}/************************ 3. Create/Close分发例程 ************************/NTSTATUSDispatchCreateClose(PDEVICE_OBJECT pDeviceObj,PIRP pIrp){PDEVICE_EXTENSION pDevExt=(PDEVICE_EXTENSION)pDeviceObj->DeviceExtension;NTSTATUS status=STATUS_SUCCESS;// 模拟:打开设备时标记在线状态if(pIrp->CurrentLocation==1&&pIrp->MajorFunction==IRP_MJ_CREATE){pDevExt->stStatus.bOnline=TRUE;DbgPrint("Device Opened!\n");}// 关闭设备时标记离线elseif(pIrp->CurrentLocation==1&&pIrp->MajorFunction==IRP_MJ_CLOSE){pDevExt->stStatus.bOnline=FALSE;DbgPrint("Device Closed!\n");}// 完成IRPpIrp->IoStatus.Status=status;pIrp->IoStatus.Information=0;IoCompleteRequest(pIrp,IO_NO_INCREMENT);returnstatus;}/************************ 4. DeviceControl分发例程(核心) ************************/NTSTATUSDispatchDeviceControl(PDEVICE_OBJECT pDeviceObj,PIRP pIrp){NTSTATUS status=STATUS_SUCCESS;PIO_STACK_LOCATION pIoStack=IoGetCurrentIrpStackLocation(pIrp);PDEVICE_EXTENSION pDevExt=(PDEVICE_EXTENSION)pDeviceObj->DeviceExtension;ULONG ulIoControlCode=pIoStack->Parameters.DeviceIoControl.IoControlCode;ULONG ulInputLen=pIoStack->Parameters.DeviceIoControl.InputBufferLength;ULONG ulOutputLen=pIoStack->Parameters.DeviceIoControl.OutputBufferLength;DbgPrint("DispatchDeviceControl: IOCTL=0x%X\n",ulIoControlCode);/************************ 处理IOCTL_SET_TIMEOUT ************************/if(ulIoControlCode==IOCTL_SET_TIMEOUT){// 校验输入缓冲区大小if(ulInputLen!=sizeof(DEV_TIMEOUT)){status=STATUS_INVALID_PARAMETER;DbgPrint("IOCTL_SET_TIMEOUT: Input buffer size error!\n");gotoEnd;}// 读取用户态下发的超时参数PDEV_TIMEOUT pTimeout=(PDEV_TIMEOUT)pIrp->AssociatedIrp.SystemBuffer;// 保存到设备扩展pDevExt->stTimeout=*pTimeout;DbgPrint("Set Timeout: Read=%dms, Write=%dms, Ctrl=%dms\n",pTimeout->dwReadTimeout,pTimeout->dwWriteTimeout,pTimeout->dwCtrlTimeout);}/************************ 处理IOCTL_GET_DEVICE_STATUS ************************/elseif(ulIoControlCode==IOCTL_GET_DEVICE_STATUS){// 校验输出缓冲区大小if(ulOutputLen!=sizeof(DEV_STATUS)){status=STATUS_INVALID_PARAMETER;DbgPrint("IOCTL_GET_DEVICE_STATUS: Output buffer size error!\n");gotoEnd;}// 将设备状态写入输出缓冲区(返回给用户态)PDEV_STATUS pStatus=(PDEV_STATUS)pIrp->AssociatedIrp.SystemBuffer;*pStatus=pDevExt->stStatus;// 设置返回数据长度pIrp->IoStatus.Information=sizeof(DEV_STATUS);DbgPrint("Get Status: Online=%d, ErrorCount=%d\n",pStatus->bOnline,pStatus->dwErrorCount);}/************************ 处理IOCTL_WRITE_DATA ************************/elseif(ulIoControlCode==IOCTL_WRITE_DATA){// 校验输入缓冲区大小if(ulInputLen!=sizeof(DEV_DATA)){status=STATUS_INVALID_PARAMETER;DbgPrint("IOCTL_WRITE_DATA: Input buffer size error!\n");gotoEnd;}// 读取用户态下发的数据PDEV_DATA pData=(PDEV_DATA)pIrp->AssociatedIrp.SystemBuffer;if(pData->dwDataLen>1024){// 校验数据长度status=STATUS_BUFFER_OVERFLOW;pData->dwErrorCode=STATUS_BUFFER_OVERFLOW;DbgPrint("IOCTL_WRITE_DATA: Data too long!\n");gotoEnd;}// 将数据拷贝到设备内部缓存RtlCopyMemory(pDevExt->szDevBuffer,pData->szBuffer,pData->dwDataLen);pDevExt->dwDevBufferLen=pData->dwDataLen;pData->dwErrorCode=STATUS_SUCCESS;// 写入成功pIrp->IoStatus.Information=sizeof(DEV_DATA);DbgPrint("Write Data: Len=%d, Data=%s\n",pData->dwDataLen,pData->szBuffer);}/************************ 处理IOCTL_READ_DATA ************************/elseif(ulIoControlCode==IOCTL_READ_DATA){// 校验输出缓冲区大小if(ulOutputLen!=sizeof(DEV_DATA)){status=STATUS_INVALID_PARAMETER;DbgPrint("IOCTL_READ_DATA: Output buffer size error!\n");gotoEnd;}// 读取设备内部缓存数据,返回给用户态PDEV_DATA pData=(PDEV_DATA)pIrp->AssociatedIrp.SystemBuffer;RtlCopyMemory(pData->szBuffer,pDevExt->szDevBuffer,pDevExt->dwDevBufferLen);pData->dwDataLen=pDevExt->dwDevBufferLen;pData->dwErrorCode=STATUS_SUCCESS;pIrp->IoStatus.Information=sizeof(DEV_DATA);DbgPrint("Read Data: Len=%d, Data=%s\n",pData->dwDataLen,pData->szBuffer);}/************************ 未知IOCTL ************************/else{status=STATUS_NOT_SUPPORTED;DbgPrint("Unsupported IOCTL: 0x%X\n",ulIoControlCode);gotoEnd;}End:// 完成IRPpIrp->IoStatus.Status=status;IoCompleteRequest(pIrp,IO_NO_INCREMENT);returnstatus;}四、步骤3:用户态实现(ioapist.c+ 测试程序)
1. 封装API实现(ioapist.c)
#include<windows.h>#include<stdio.h>#include"ioapist.h"/************************ 1. 打开设备 ************************/HANDLE __stdcallDevOpen(LPCWSTR lpDevicePath,DWORD dwDesiredAccess){if(lpDevicePath==NULL){lpDevicePath=DEFAULT_DEVICE_PATH;}// 打开设备(需管理员权限)HANDLE hDevice=CreateFileW(lpDevicePath,dwDesiredAccess,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);if(hDevice==INVALID_HANDLE_VALUE){DWORD dwErr=GetLastError();printf("DevOpen failed! ErrCode=0x%X\n",dwErr);returnNULL;}returnhDevice;}/************************ 2. 关闭设备 ************************/VOID __stdcallDevClose(HANDLE hDevice){if(hDevice!=NULL&&hDevice!=INVALID_HANDLE_VALUE){CloseHandle(hDevice);printf("DevClose success!\n");}}/************************ 3. 设置超时 ************************/BOOL __stdcallDevSetTimeout(HANDLE hDevice,PDEV_TIMEOUT pTimeout){if(hDevice==NULL||pTimeout==NULL){SetLastError(ERROR_INVALID_PARAMETER);returnFALSE;}DWORD dwBytesReturned=0;BOOL bResult=DeviceIoControl(hDevice,IOCTL_SET_TIMEOUT,pTimeout,sizeof(DEV_TIMEOUT),NULL,0,&dwBytesReturned,NULL);if(!bResult){DWORD dwErr=GetLastError();printf("DevSetTimeout failed! ErrCode=0x%X\n",dwErr);}else{printf("DevSetTimeout success! Read=%dms, Write=%dms, Ctrl=%dms\n",pTimeout->dwReadTimeout,pTimeout->dwWriteTimeout,pTimeout->dwCtrlTimeout);}returnbResult;}/************************ 4. 获取设备状态 ************************/BOOL __stdcallDevGetStatus(HANDLE hDevice,PDEV_STATUS pStatus){if(hDevice==NULL||pStatus==NULL){SetLastError(ERROR_INVALID_PARAMETER);returnFALSE;}DWORD dwBytesReturned=0;BOOL bResult=DeviceIoControl(hDevice,IOCTL_GET_DEVICE_STATUS,NULL,0,pStatus,sizeof(DEV_STATUS),&dwBytesReturned,NULL);if(!bResult){DWORD dwErr=GetLastError();printf("DevGetStatus failed! ErrCode=0x%X\n",dwErr);}else{printf("DevGetStatus success! Online=%d, ErrorCount=%d, BufferSize=%d\n",pStatus->bOnline,pStatus->dwErrorCount,pStatus->dwBufferSize);}returnbResult;}/************************ 5. 写数据 ************************/BOOL __stdcallDevWriteData(HANDLE hDevice,PDEV_DATA pData){if(hDevice==NULL||pData==NULL){SetLastError(ERROR_INVALID_PARAMETER);returnFALSE;}DWORD dwBytesReturned=0;BOOL bResult=DeviceIoControl(hDevice,IOCTL_WRITE_DATA,pData,sizeof(DEV_DATA),pData,// 输出错误码到同一个结构体sizeof(DEV_DATA),&dwBytesReturned,NULL);if(!bResult){DWORD dwErr=GetLastError();printf("DevWriteData failed! ErrCode=0x%X\n",dwErr);}else{printf("DevWriteData success! Len=%d, Data=%s, ErrCode=0x%X\n",pData->dwDataLen,pData->szBuffer,pData->dwErrorCode);}returnbResult;}/************************ 6. 读数据 ************************/BOOL __stdcallDevReadData(HANDLE hDevice,PDEV_DATA pData){if(hDevice==NULL||pData==NULL){SetLastError(ERROR_INVALID_PARAMETER);returnFALSE;}DWORD dwBytesReturned=0;BOOL bResult=DeviceIoControl(hDevice,IOCTL_READ_DATA,NULL,0,pData,sizeof(DEV_DATA),&dwBytesReturned,NULL);if(!bResult){DWORD dwErr=GetLastError();printf("DevReadData failed! ErrCode=0x%X\n",dwErr);}else{printf("DevReadData success! Len=%d, Data=%s, ErrCode=0x%X\n",pData->dwDataLen,pData->szBuffer,pData->dwErrorCode);}returnbResult;}2. 用户态测试程序(TestApp.c)
#include<windows.h>#include<stdio.h>#include"ioapist.h"intmain(){HANDLE hDevice=NULL;DEV_TIMEOUT stTimeout={0};DEV_STATUS stStatus={0};DEV_DATA stWriteData={0};DEV_DATA stReadData={0};/************************ 1. 打开设备 ************************/hDevice=DevOpen(DEFAULT_DEVICE_PATH,GENERIC_READ|GENERIC_WRITE);if(hDevice==NULL){printf("Open Device Failed!\n");return-1;}printf("Open Device Success!\n");/************************ 2. 设置超时 ************************/stTimeout.dwReadTimeout=6000;// 6秒stTimeout.dwWriteTimeout=4000;// 4秒stTimeout.dwCtrlTimeout=3000;// 3秒if(!DevSetTimeout(hDevice,&stTimeout)){gotoCleanup;}/************************ 3. 获取设备状态 ************************/if(!DevGetStatus(hDevice,&stStatus)){gotoCleanup;}/************************ 4. 写数据到设备 ************************/charszWriteBuf[]="Hello Custom Device!";RtlCopyMemory(stWriteData.szBuffer,szWriteBuf,strlen(szWriteBuf));stWriteData.dwDataLen=strlen(szWriteBuf);if(!DevWriteData(hDevice,&stWriteData)){gotoCleanup;}/************************ 5. 从设备读数据 ************************/RtlZeroMemory(&stReadData,sizeof(DEV_DATA));if(!DevReadData(hDevice,&stReadData)){gotoCleanup;}/************************ 6. 清理资源 ************************/Cleanup:DevClose(hDevice);printf("Test App Exit!\n");return0;}五、编译与运行说明
1. 驱动编译(WDK环境)
- 依赖:Windows Driver Kit(WDK 10+);
- 配置:驱动项目属性中,选择“Kernel Mode Driver”,平台选择x64/x86;
- 输出:生成
CustomDev.sys驱动文件。
2. 用户态编译(VS环境)
- 依赖:Visual Studio 2019+,Windows SDK;
- 配置:控制台项目,将
ioapist.h、ioapist.c、TestApp.c加入项目; - 编译选项:启用
Unicode,平台选择与驱动一致(x64/x86); - 输出:生成
TestApp.exe可执行文件。
3. 运行步骤
- 安装驱动:通过
sc create CustomDev type= kernel binPath= "C:\CustomDev.sys"创建服务,sc start CustomDev启动驱动; - 以管理员权限运行
TestApp.exe; - 查看输出:控制台会打印各步骤结果,驱动侧可通过
DebugView查看DbgPrint日志; - 卸载驱动:
sc stop CustomDev+sc delete CustomDev。
六、关键细节与注意事项
- 权限要求:用户态程序需管理员权限(否则
CreateFile打开设备失败); - 结构体对齐:驱动和用户态的结构体必须保证内存对齐(避免数据解析错误);
- 错误处理:
- 驱动侧:通过
DbgPrint打印调试信息,用NT_SUCCESS判断状态; - 用户态:通过
GetLastError获取错误码,常见错误:ERROR_INVALID_HANDLE:设备句柄无效;ERROR_NOT_SUPPORTED:驱动不支持该IOCTL;ERROR_ACCESS_DENIED:无管理员权限;
- 驱动侧:通过
- 缓冲区方式:示例中用
METHOD_BUFFERED(最通用),驱动侧通过pIrp->AssociatedIrp.SystemBuffer访问数据; - 符号链接:驱动创建的符号链接
\\DosDevices\\CustomDevice对应用户态的\\\\.\\CustomDevice,需保证名称一致。
七、运行预期输出(用户态控制台)
Open Device Success! DevSetTimeout success! Read=6000ms, Write=4000ms, Ctrl=3000ms DevGetStatus success! Online=1, ErrorCount=0, BufferSize=1024 DevWriteData success! Len=19, Data=Hello Custom Device!, ErrCode=0x0 DevReadData success! Len=19, Data=Hello Custom Device!, ErrCode=0x0 DevClose success! Test App Exit!该示例完整覆盖了“驱动初始化→用户态打开设备→下发参数→数据交互→关闭设备→驱动卸载”全流程,可直接基于此扩展更多功能(如设备错误处理、超时触发逻辑等)。