重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
本文仅针对于3.0及上版本的SylixOS x86平台PCI转串口相关驱动架构进行简单的分析。
哈密网站制作公司哪家好,找成都创新互联!从网页设计、网站建设、微信开发、APP开发、成都响应式网站建设公司等网站项目制作,到程序开发,运营维护。成都创新互联2013年开创至今到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选成都创新互联。
外部链接标准(或称个人电脑界面,Personal Computer Interface),实际应用中简称为PCI(Peripheral Component Interconnect),是一种连接电脑主板和外部设备的总线标准。一般PCI装置可分为以下两种形式:
直接内建于主板上的集成电路,在PCI规范中称作“嵌入装置”(planar device);或者安装在插槽上的扩充界面卡。
PCI 总线见于现代的个人电脑中,并已取代了ISA和VESA局部总线,成为了标准扩充总线。PCI总线亦常见于其他电脑类型中。PCI总线最终将被PCI Express和其他更先进的技术取代,这些技术现在已经被用于最新款的电脑中。
PCI规范规定了该总线的物理尺寸(包括线宽)、电气特性、总线时序和协议。该规范可从美国PCI-SIG协会购得。
常见的PCI卡包括网络卡、声卡、调变解调器(调制解调器)、电视卡和硬盘控制器等,另外还有USB和串列埠等端口。原本显卡通常也是PCI装置,但很快其频宽已不足以支援显卡的性能。PCI显卡现在仅用在需要额外的外接显示器或主板上没有AGP和PCI Express槽的情况。
串口卡主要是用来扩展PC的串口数量和种类。常见的x86机器主板上可能只有一个或者两个RS232的串口接口,在某些场景下不能满足对串口的需求,于是就有了PCI串口卡。通常PCI串口卡会支持拓展2至8个串口,也会支持RS232,RS485,RS422这几种串口格式。PCI串口卡在工业和军工领域运用广泛。
在x86的base工程libsylixos/SylixOS/driver/pci/null路径下,提供了SylixOS PCI驱动示例:pciNullDev.c。
pciNullDev.c中主要实现了如表 41所示五个主体框架函数。
表 41 pciNullDev.c中主体函数
函数名 | 函数功能 |
pciNullDevInit | PCI设备驱动初始化 |
pciNullDevProbe | PCI设备ID探测和资源信息初始化 |
pciNullDevRemove | 删除PCI设备 |
pciNullDevIdTblGet | 获取PCI设备ID表的表头与表头大小 |
pciNullDevIsr | PCI设备驱动中断服务程序 |
函数pciNullDevInit
该函数主要用来初始化PCI设备驱动,其调用pciNullDevIdTblGet等函数将相关的PCI设备结构体填充完成,并调用API_PciDrvRegister函数注册PCI设备驱动。
函数pciNullDevProbe
该函数由SylixOS PCI子系统回调,主要完成更新设备驱动版本信息,设备索引号,获取设备MEM、IO、IRQ等资源信息以及中断连接与使能操作。
函数pciNullDevRemove
该函数由SylixOS PCI子系统回调,主要完成删除PCI设备的一系列操作,在该示例中没有实现相关功能代码。
函数pciNullDevIdTblGet
该函数主要由pciNullDevInit函数调用,用来获取相关PCI设备的ID表的表头与表的大小。
函数pciNullDevIsr
该函数为驱动服务函数,主要提供了该PCI设备驱动的中断服务处理,在该示例中中断服务处理没有实现相关功能代码。
pciNullDev.c示例中的PCI设备驱动的流程如图 41所示:
图 41 pciNullDev.c设备驱动大致流程
在x86的base工程libsylixos/SylixOS/driver/pci/sio路径存放的是PCI串口卡驱动。pciSioExar.c和pciSioNetmos.c均是PCI串口卡的驱动,是针对不同厂商的适配。一般PCI串口卡都是使用了16c500这一系列的串口芯片,这里着重分析pciSioNetmos.c。
如程序清单 41所示pciSioNetmos.c中有一个驱动支持的设备ID表结构体数组。PCI驱动通过PCI总线获取设备相关ID数据和驱动中的驱动支持设备ID表来匹配加载相关的驱动。
程序清单 41 驱动支持设备ID表
/********************************************************************************************************* 驱动支持的设备 ID 表, 用于驱动与设备进行自动匹配, 与 Linux 参数保持一致. *********************************************************************************************************/ staticconstPCI_DEV_ID_CB pciSioNetmosIdTbl[] = { { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9901, 0xa000, 0x1000, 0, 0, netmos_9912 }, { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9912, 0xa000, 0x1000, 0, 0, netmos_9912 }, { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9922, 0xa000, 0x1000, 0, 0, netmos_9912 }, { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9904, 0xa000, 0x1000, 0, 0, netmos_9912 }, { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9900, 0xa000, 0x1000, 0, 0, netmos_9912 }, { } /* terminatelist */ }
如程序清单 42,在x86的base工程libsylixos/SylixOS/system/drvice/pci/pciDrv.h中定义了设备ID表数据结构体PCI_DEV_ID_CB,其中包含厂商ID,设备ID,子厂商ID,子设备ID,设备类,设备子类,设备私有数据这7个相关属性,与Linux的PCI结构一致。
程序清单 42 驱动支持设备ID表结构体
/********************************************************************************************************* 驱动支持设备列表控制块 *********************************************************************************************************/ typedefstruct { UINT32 PCIDEVID_uiVendor; /* 厂商 ID */ UINT32 PCIDEVID_uiDevice; /* 设备 ID */ UINT32 PCIDEVID_uiSubVendor; /* 子厂商 ID */ UINT32 PCIDEVID_uiSubDevice; /* 子设备 ID */ UINT32 PCIDEVID_uiClass; /* 设备类 */ UINT32 PCIDEVID_uiClassMask; /* 设备子类 */ ULONG PCIDEVID_ulData; /* 设备私有数据 */ } PCI_DEV_ID_CB;
如表 42所示在pciSioNetmos.c除了实现了和示例驱动中类似的Init、Probe、Remove、IdTblGet、Isr这五个相关类型的函数外,还实现了其他的设备相关驱动的函数。
表 4-2 pciSioNetmos.c实现的相关函数
函数名 | 函数功能 |
pciSioNetmosInit | PCI NETMOS 16c550 控制器驱动相关初始化 |
pciSioNetmosProbe | PCI NETMOS 16c550 板卡驱动探测设备 |
pciSioNetmosRemove | 总线上移除 PCI 设备 |
pciSioNetmosIdTblGet | 获取PCI设备ID表的表头与表头大小 |
pciSioNetmosChan | 创建一个 SIO 通道 |
pciSioNetmosIsr | PCI设备驱动中断服务程序 |
pciSioNetmosGetReg | 获得 NETMOS 16C550 寄存器的值 |
pciSioNetmosGetReg | 设置 NETMOS 16C550 寄存器 |
函数pciSioNetmosInit
该函数和pciNullDevInit一样,调用pciNullDevIdTblGet获取驱动支持设备ID表的表头和大小,并设置驱动名为“pci_netmos”,pciSioNetmosProbe和pciSioNetmosRemove复制给PCI设备驱动控制块,调用API_PciDrvRegister函数注册PCI设备驱动。
函数pciSioNetmosProbe
该函数通过驱动设置的参数获取设备MEM的其实地址和MEM的大小,通过调用API_PciDevIoRemap重新映射驱动的内存空间地址,根据驱动设置的参数获取设备中断资源并注册,启动PCI总线的主模式,并调用pciSioNetmosChan函数来初始化串口设备的通道参数,最后通过ttyDevCreate函数创建出串口设备。
函数pciSioNetmosRemove
和函数pciNullDevRemove一样,实现总线上移除PCI设备时的处理,这里在pciSioNetmos.c里面没有实现相关方法。
函数pciSioNetmosIdTblGet
和pciNullDevIdTblGet一样,用来从驱动支持设备ID表中获取相关PCI设备的ID表的表头与表的大小。
函数pciSioNetmosChan
PCI串口驱动的关键函数,该函数将PCI设备驱动和串口设备驱动相互连接起来了。将驱动设置好的串口参数,PCI串口的中断和pciSioNetmosSetReg,pciSioNetmosGetReg函数赋值给PCI设备串口通道结构体,调用API_PciDevInterDisable先禁能PCI串口设备的中断,然后调用系统的16c550串口驱动中的sio16c550Init来初始化相关PCI串口通道,随后调用API_PciDevInterConnect,API_PciDevInterEnable连接并使能PCI串口设备中断,完成PCI串口通道的创建。
函数pciSioNetmosIsr
PCI串口的中断服务函数,该函数是在PCI设备的中断函数服务中调用了系统的16c550串口驱动服务函数,来完成对应的串口中断处理事务。
函数pciSioNetmosGetReg
该函数被系统串口驱动回调,用于读取PCI设备对应通道相关寄存器地址的值。
函数pciSioNetmosSetReg
该函数被系统串口驱动回调,用于设置PCI设备对应通道相关寄存器地址的值。
pciSioNetmos.c示例中的PCI设备驱动的函数结构如图 44所示:
图 44 pciSioNetmos.c设备驱动大体流程
PCI串口驱动本质上是PCI驱动和串口驱动的一个结合,上层通过系统的串口驱动来封装出串口所需要的操作接口,下层由PCI驱动来和PCI总线上的设备进行各种操作。