zoukankan      html  css  js  c++  java
  • 35、PCI设备驱动简介

    PCI(Peripheral Component Interconnect)总线标准是一种将系统外部设备连接起来的总线标准,速度可以达到133MB/s,它是PC中最重要的总线,其他总路线如ISA总线,USB总线等,都挂载在PCI总线上(通过桥接电路)。由Intel推出的一种局部总线,为32位数据地址总线,可以扩展为64位,支持突发读写,及多组外围设备。

    PCI系统中,Host/PCI称为北桥,连接主处理器总线到基础PCI局部总线;PCI-ISA桥称为南桥,连接基础PCI总线到ISA总线。其中南桥通常还含有中断控制器,IDE控制器,USB控制器和DMA控制器等设备。

    wps_clip_image-27502

    图示 P412

    PCI有三个相互独立的物理地址空间:设备存储器地址空间,I/O地址空间和配置空间。由于PCI支持设备即插即用,所以PCI设备不占用固定的内存地址空间或I/O地址空间,而是可以由操作系统决定其映射的基址。

    PCI总线规范定义的配置Hha总长度为256个字节,配置信息按一定的顺序和大小依次存放。根据读取PCI配置空间,可以得到PCI设备的所有资源。[1]中讲述了多种读取PCI配置空间的方法,包括通过最基本的I/O端口操作进行读取,通过DDK提供的函数HalGetBusData,HalSetBusDataNT式驱动中进行读取,在WDM驱动中的读取方法,等。

    一般程序所看到的内存指针都是虚拟内存,如果想操作物理内存,必须使用DDK提供的内核函数WRITE_REGISTER_XX,READ_REGISTER_XX系列函数。

    MmAllocateContiguousMemory分配连续的物理地址,MmGetPhysicalAddress得到连续的物理内存地址。

    代码
    #pragma PAGEDCODE
    NTSTATUS InitMyPCI(IN PDEVICE_EXTENSION pdx,IN PCM_PARTIAL_RESOURCE_LIST list)
    {
    PDEVICE_OBJECT fdo
    = pdx->fdo;

    ULONG vector;
    KIRQL irql;
    KINTERRUPT_MODE mode;
    KAFFINITY affinity;
    BOOLEAN irqshare;
    BOOLEAN gotinterrupt
    = FALSE;

    PHYSICAL_ADDRESS portbase;
    BOOLEAN gotport
    = FALSE;

    PCM_PARTIAL_RESOURCE_DESCRIPTOR resource
    = &list->PartialDescriptors[0];
    ULONG nres
    = list->Count;
    BOOLEAN IsMem0
    = TRUE;
    for (ULONG i = 0; i < nres; ++i, ++resource)
    {
    // for each resource
    switch (resource->Type)
    {
    // switch on resource type
    case CmResourceTypePort:
    portbase
    = resource->u.Port.Start;
    pdx
    ->nports = resource->u.Port.Length;
    pdx
    ->mappedport = (resource->Flags & CM_RESOURCE_PORT_IO) == 0;
    gotport
    = TRUE;
    break;

    case CmResourceTypeMemory:
    if (IsMem0)
    {
    pdx
    ->MemBar0 = (PUCHAR)MmMapIoSpace(resource->u.Memory.Start,
    resource
    ->u.Memory.Length,
    MmNonCached);
    pdx
    ->nMem0 = resource->u.Memory.Length;
    IsMem0
    = FALSE;
    }
    else
    {
    pdx
    ->MemBar1 = (PUCHAR)MmMapIoSpace(resource->u.Memory.Start,
    resource
    ->u.Memory.Length,
    MmNonCached);
    pdx
    ->nMem1 = resource->u.Memory.Length;
    }

    break;

    case CmResourceTypeInterrupt:
    irql
    = (KIRQL) resource->u.Interrupt.Level;
    vector
    = resource->u.Interrupt.Vector;
    affinity
    = resource->u.Interrupt.Affinity;
    mode
    = (resource->Flags == CM_RESOURCE_INTERRUPT_LATCHED)
    ? Latched : LevelSensitive;
    irqshare
    = resource->ShareDisposition == CmResourceShareShared;
    gotinterrupt
    = TRUE;

    break;

    default:
    KdPrint((
    "Unexpected I/O resource type %d\n", resource->Type));
    break;
    }
    // switch on resource type
    } // for each resource

    if (!(TRUE&& gotport&& gotinterrupt ))
    {
    KdPrint((
    " Didn't get expected I/O resources\n"));
    return STATUS_DEVICE_CONFIGURATION_ERROR;
    }

    if (pdx->mappedport)
    {
    // map port address for RISC platform
    pdx->portbase = (PUCHAR) MmMapIoSpace(portbase, pdx->nports, MmNonCached);
    if (!pdx->mappedport)
    {
    KdPrint((
    "Unable to map port range %I64X, length %X\n", portbase, pdx->nports));
    return STATUS_INSUFFICIENT_RESOURCES;
    }
    }
    // map port address for RISC platform
    else
    pdx
    ->portbase = (PUCHAR) portbase.QuadPart;

    NTSTATUS status
    = IoConnectInterrupt(&pdx->InterruptObject, (PKSERVICE_ROUTINE) OnInterrupt,
    (PVOID) pdx, NULL, vector, irql, irql, LevelSensitive, TRUE, affinity, FALSE);
    if (!NT_SUCCESS(status))
    {
    KdPrint((
    "IoConnectInterrupt failed - %X\n", status));
    if (pdx->portbase && pdx->mappedport)
    MmUnmapIoSpace(pdx
    ->portbase, pdx->nports);
    pdx
    ->portbase = NULL;
    return status;
    }

    #define IMAGE_LENGTH (640*480)
    //申请一段连续物理地址来读取图像
    PHYSICAL_ADDRESS maxAddress;
    maxAddress.u.LowPart
    = 0xFFFFFFFF;
    maxAddress.u.HighPart
    = 0;

    pdx
    ->MemForImage = MmAllocateContiguousMemory(IMAGE_LENGTH,maxAddress);

    PHYSICAL_ADDRESS pycialAddressForImage
    = MmGetPhysicalAddress(pdx->MemForImage);

    WRITE_REGISTER_BUFFER_UCHAR((PUCHAR)pdx
    ->MemBar0+0x10000,
    (PUCHAR)
    &pycialAddressForImage.u.LowPart,4);

    return STATUS_SUCCESS;
    }
    示例代码 P428

    参考

    [1] Windows 驱动开发技术详解,张帆

  • 相关阅读:
    jmeter获取当前时间、时间运算、时间比较、时间转换
    jmeter实现sha256算法加密
    用FinalShell连接linux服务器
    dstat:except getopt.error, exc:
    新书上线:《Spring Boot+Spring Cloud+Vue+Element项目实战:手把手教你开发权限管理系统》,欢迎大家买回去垫椅子垫桌脚
    Spring Cloud 教程
    使用VMware Workstation Player虚拟机安装Linux系统
    Java并发编程:Java实现多线程的几种方式
    Java并发编程:Java中的锁和线程同步机制
    Spring Boot:使用Rabbit MQ消息队列
  • 原文地址:https://www.cnblogs.com/mydomain/p/1898480.html
Copyright © 2011-2022 走看看