searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

windows驱动 串口的过滤

2024-11-28 09:53:12
18
0

知识点

  1. 串口设备命名规则:Windows中串口设备具有固定的名字,第一个串口叫"\Device\Serial0",第二个叫"\Device\Serial1"。

  2. 快速构造UNICODE_STRING:可以直接使用RTL_CONSTANT_STRING宏来快速构造UNICODE_STRING,例如UNICODE_STRING com_name = RTL_CONSTANT_STRING(L"\\Device\\Serial0");

  3. 过滤设备名称:过滤设备一般不需要名称,IoCreateDevice传入NULL即可。

  4. 设备对象生成:一个驱动中生成从属于其他驱动的设备对象,理论上是可以的。

  5. IRP请求:串口设备接受到的请求都是IRP(I/O Request Packet)。

  6. 设备卸载APIIoDetachDeviceIoDeleteDevice用于设备卸载,KeDelayExecutionThread用于等待IRP处理结束。

  7. 设备绑定APIIoAttachDevice用于绑定有名设备,IoAttachDeviceToDeviceStackIoAttachDeviceToDeviceStackSafe用于绑定无名设备。

  8. 获取IRP数据:从IRP中获取缓冲区和长度,用于读取或写入数据。

操作Demo

以下是一个简单的串口过滤驱动的示例代码:

  1. 驱动入口函数
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObj, IN PUNICODE_STRING RegistryPath) {
    size_t i;
    for(i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
        DriverObj->MajorFunction[i] = ccpDispatch;
    }
    DriverObj->DriverUnload = ccpUnload;
    ccpAttachAlloComs(DriverObj);
    return STATUS_SUCCESS;
}
  1. 派遣函数
NTSTATUS ccpDispatch(PDEVICE_OBJECT device, PIRP irp) {
    PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
    NTSTATUS status;
    ULONG i, j;
    for(i = 0; i < CCP_MAX_COM_ID; i++) {
        if(s_fltobj[i] == device) {
            if(irpsp->MajorFunction == IRP_MJ_POWER) {
                PoStartNextPowerIrp(irp);
                IoSkipCurrentIrpStackLocation(irp);
                return IoCallDriver(s_nextobj[i], irp);
            }
            if(irpsp->MajorFunction == IRP_MJ_WRITE) {
                ULONG len = irpsp->Parameters.Write.Length;
                PUCHAR buf = NULL;
                if(irp->MdlAddress != NULL) {
                    buf = (PUCHAR)MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
                } else {
                    buf = (PUCHAR)irp->UserBuffer;
                }
                if(buf == NULL) {
                    buf = (PUCHAR)irp->AssociatedIrp.SystemBuffer;
                }
                for(j = 0; j < len; j++) {
                    KdPrint(("comcap:Send Data: %2x\r\n", buf[j]));
                }
            }
            IoSkipCurrentIrpStackLocation(irp);
            return IoCallDriver(s_nextobj[i], irp);
        }
    }
    irp->IoStatus.Information = 0;
    irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
    IoCompleteRequest(irp, IO_NO_INCREMENT);
    return STATUS_SUCCESS;
}
  1. 驱动卸载函数
void ccpUnload(PDRIVER_OBJECT drv) {
    ULONG i;
    LARGE_INTEGER interval;
    for(i = 0; i < CCP_MAX_COM_ID; i++) {
        if(s_nextobj[i] != NULL) {
            IoDeleteDevice(s_nextobj[i]);
        }
    }
    interval.QuadPart = (5*1000*DELAY_ONE_MILLISECOND);
    KeDelayExecutionThread(KernelMode, FALSE, &interval);
    for(i = 0; i < CCP_MAX_COM_ID; i++) {
        if(s_nextobj[i] != NULL) {
            IoDeleteDevice(s_fltobj[i]);
        }
    }
}
  1. 创建过滤设备并绑定
NTSTATUS ccpAttachDevice(PDRIVER_OBJECT driverObj, PDEVICE_OBJECT oldDev, PDEVICE_OBJECT *fltObj, PDEVICE_OBJECT *next) {
    NTSTATUS status;
    PDEVICE_OBJECT topDev = NULL;
    status = IoCreateDevice(driverObj, 0, NULL, oldDev->DeviceType, 0, FALSE, fltObj);
    if(status != STATUS_SUCCESS) {
        return status;
    }
    if(oldDev->Flags & DO_BUFFERED_IO) {
        (*fltObj)->Flags |= DO_BUFFERED_IO;
    } else if(oldDev->Flags & DO_DIRECT_IO) {
        (*fltObj)->Flags |= DO_DIRECT_IO;
    } else if(oldDev->Characteristics & FILE_DEVICE_SECURE_OPEN) {
        (*fltObj)->Characteristics |= FILE_DEVICE_SECURE_OPEN;
    }
    (*fltObj)->Flags |= DO_POWER_PAGABLE;
    topDev = IoAttachDeviceToDeviceStack(*fltObj, oldDev);
    if(topDev == NULL) {
        IoDeleteDevice(*fltObj);
        *fltObj = NULL;
        status = STATUS_SUCCESS;
        return status;
    }
    *next = topDev;
    return STATUS_SUCCESS;
}
0条评论
作者已关闭评论
张伯雄
3文章数
0粉丝数
张伯雄
3 文章 | 0 粉丝
张伯雄
3文章数
0粉丝数
张伯雄
3 文章 | 0 粉丝
原创

windows驱动 串口的过滤

2024-11-28 09:53:12
18
0

知识点

  1. 串口设备命名规则:Windows中串口设备具有固定的名字,第一个串口叫"\Device\Serial0",第二个叫"\Device\Serial1"。

  2. 快速构造UNICODE_STRING:可以直接使用RTL_CONSTANT_STRING宏来快速构造UNICODE_STRING,例如UNICODE_STRING com_name = RTL_CONSTANT_STRING(L"\\Device\\Serial0");

  3. 过滤设备名称:过滤设备一般不需要名称,IoCreateDevice传入NULL即可。

  4. 设备对象生成:一个驱动中生成从属于其他驱动的设备对象,理论上是可以的。

  5. IRP请求:串口设备接受到的请求都是IRP(I/O Request Packet)。

  6. 设备卸载APIIoDetachDeviceIoDeleteDevice用于设备卸载,KeDelayExecutionThread用于等待IRP处理结束。

  7. 设备绑定APIIoAttachDevice用于绑定有名设备,IoAttachDeviceToDeviceStackIoAttachDeviceToDeviceStackSafe用于绑定无名设备。

  8. 获取IRP数据:从IRP中获取缓冲区和长度,用于读取或写入数据。

操作Demo

以下是一个简单的串口过滤驱动的示例代码:

  1. 驱动入口函数
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObj, IN PUNICODE_STRING RegistryPath) {
    size_t i;
    for(i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
        DriverObj->MajorFunction[i] = ccpDispatch;
    }
    DriverObj->DriverUnload = ccpUnload;
    ccpAttachAlloComs(DriverObj);
    return STATUS_SUCCESS;
}
  1. 派遣函数
NTSTATUS ccpDispatch(PDEVICE_OBJECT device, PIRP irp) {
    PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
    NTSTATUS status;
    ULONG i, j;
    for(i = 0; i < CCP_MAX_COM_ID; i++) {
        if(s_fltobj[i] == device) {
            if(irpsp->MajorFunction == IRP_MJ_POWER) {
                PoStartNextPowerIrp(irp);
                IoSkipCurrentIrpStackLocation(irp);
                return IoCallDriver(s_nextobj[i], irp);
            }
            if(irpsp->MajorFunction == IRP_MJ_WRITE) {
                ULONG len = irpsp->Parameters.Write.Length;
                PUCHAR buf = NULL;
                if(irp->MdlAddress != NULL) {
                    buf = (PUCHAR)MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
                } else {
                    buf = (PUCHAR)irp->UserBuffer;
                }
                if(buf == NULL) {
                    buf = (PUCHAR)irp->AssociatedIrp.SystemBuffer;
                }
                for(j = 0; j < len; j++) {
                    KdPrint(("comcap:Send Data: %2x\r\n", buf[j]));
                }
            }
            IoSkipCurrentIrpStackLocation(irp);
            return IoCallDriver(s_nextobj[i], irp);
        }
    }
    irp->IoStatus.Information = 0;
    irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
    IoCompleteRequest(irp, IO_NO_INCREMENT);
    return STATUS_SUCCESS;
}
  1. 驱动卸载函数
void ccpUnload(PDRIVER_OBJECT drv) {
    ULONG i;
    LARGE_INTEGER interval;
    for(i = 0; i < CCP_MAX_COM_ID; i++) {
        if(s_nextobj[i] != NULL) {
            IoDeleteDevice(s_nextobj[i]);
        }
    }
    interval.QuadPart = (5*1000*DELAY_ONE_MILLISECOND);
    KeDelayExecutionThread(KernelMode, FALSE, &interval);
    for(i = 0; i < CCP_MAX_COM_ID; i++) {
        if(s_nextobj[i] != NULL) {
            IoDeleteDevice(s_fltobj[i]);
        }
    }
}
  1. 创建过滤设备并绑定
NTSTATUS ccpAttachDevice(PDRIVER_OBJECT driverObj, PDEVICE_OBJECT oldDev, PDEVICE_OBJECT *fltObj, PDEVICE_OBJECT *next) {
    NTSTATUS status;
    PDEVICE_OBJECT topDev = NULL;
    status = IoCreateDevice(driverObj, 0, NULL, oldDev->DeviceType, 0, FALSE, fltObj);
    if(status != STATUS_SUCCESS) {
        return status;
    }
    if(oldDev->Flags & DO_BUFFERED_IO) {
        (*fltObj)->Flags |= DO_BUFFERED_IO;
    } else if(oldDev->Flags & DO_DIRECT_IO) {
        (*fltObj)->Flags |= DO_DIRECT_IO;
    } else if(oldDev->Characteristics & FILE_DEVICE_SECURE_OPEN) {
        (*fltObj)->Characteristics |= FILE_DEVICE_SECURE_OPEN;
    }
    (*fltObj)->Flags |= DO_POWER_PAGABLE;
    topDev = IoAttachDeviceToDeviceStack(*fltObj, oldDev);
    if(topDev == NULL) {
        IoDeleteDevice(*fltObj);
        *fltObj = NULL;
        status = STATUS_SUCCESS;
        return status;
    }
    *next = topDev;
    return STATUS_SUCCESS;
}
文章来自个人专栏
文章 | 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0