SylixOS中APIC HPET定时器字符驱动实现
来源:互联网 发布:网络大电影预算表 编辑:程序博客网 时间:2024/06/06 06:54
1.简介
1.1 APIC介绍
“APIC”是Advanced Programmable Interrupt Controller的缩写,即高级可编程中断控制器。引入APIC机制是为了适应multiple processor(MP,多处理器)环境。
APIC分为两部分:Local APIC与I/O APIC。Local APIC位于处理器内部,而I/O APIC则呼吁芯片组的一部分。Local APIC与I/O APIC通过system bus进行通信。Local APIC 与I/O APIC的关系如图1.1所示。图1.1 Local APIC与I/O APIC的关系
本文档使用的HPET的中断线是连接在I/OAPIC上的。在SylixOS中仅在主机是多核且在menu.lst中加入hpet=yes参数才会启用APIC的HPET功能。
1.2 HPET的工作原理
“HPET” 是High precision event timer的缩写,即高精度定时器。HPET有1个main counter(主计数器)寄存器和最多8个timer(定时器),记为timer0~timer7定时器。每个timer有自己的一对寄存器,分别是:configure(timer配置寄存器)和comparator value(timer比较值寄存器)。
HPET counter按照固定的频率进行计数,HPET会检查counter的值与timer的comparator值进行比较。当counter的值达到任何一个timer的comparator值时将产生中断(当配置可产生中断时)。那么,如果counter同时达到了多个timer所设定comparator值就会产生多个中断。HPET的8个timer可以配置为使用不同的IRQ线,这些同时产生的中断就可以同时进行处理。
2. HPET字符设备定时器的实现正如在SylixOS中字符设备驱动的实现方式一样。HPET需要实现对应的字符设备的操作函数集并将其注册到系统中即可。和普通的字符设备不同,由于只需要实现HPET的定时功能,因此本文档中所描述的HPET字符设备定时器并没有实现读写的操作,只实现了ioctl的相关功能。
2.1 HPET的初始化HPET的初始化如程序清单2.1所示。
程序清单2.1 HPET初始化
INT bspHpetTimerInit (ACPI_TABLE_HPET *pAcpiHpetPhy, ULONG *pulVector){ ACPI_TABLE_HPET *pAcpiHpet; UINT32 ulhpetTimerCfg; /* * 映射 ACPI HPET 表 */ pAcpiHpet = bspAcpiHpetMap((addr_t)pAcpiHpetPhy, LW_CFG_VMM_PAGE_SIZE); if (!pAcpiHpet) { return (PX_ERROR); } /* * 映射 HPET 寄存器 */ __GhpetBase = (addr_t)API_VmmIoRemapNocache((PVOID)(pAcpiHpet->Address.Address), LW_CFG_VMM_PAGE_SIZE); /* * 解除映射 ACPI HPET 表 */ API_VmmIoUnmap((PVOID)(((addr_t)pAcpiHpet) & LW_CFG_VMM_PAGE_MASK)); if (!__GhpetBase) {/* 映射 HPET 寄存器失败 */ return (PX_ERROR); } __Gul32FsPerCnt = read32(HPET_ID_HI); ulhpetTimerCfg = read32(HPET_TIMER_CONFIG_LO(2));write32((((ulhpetTimerCfg & (~(ROUTE_MSK << 9))) | (LW_IRQ_20 << 9)) & /* 设置中断为edge模式并关中断 */ (~(3 <<1 ))), HPET_TIMER_CONFIG_LO(2)); *pulVector = LW_IRQ_20;/* IRQ20 */ return (ERROR_NONE);}其中bspAcpiHpetMap主要是实现ACPI HPET表的映射,实现如程序清单2.2所示。
程序清单2.2 映射ACPI HPET表
static VOID *bspAcpiHpetMap (addr_t ulAcpiPhyAddr, size_t ulAcpiSize){ addr_t ulPhyBase = ROUND_DOWN(ulAcpiPhyAddr, LW_CFG_VMM_PAGE_SIZE); addr_t ulOffset = ulAcpiPhyAddr - ulPhyBase; addr_t ulVirBase; ulAcpiSize += ulOffset; ulAcpiSize = ROUND_UP(ulAcpiSize, LW_CFG_VMM_PAGE_SIZE); ulVirBase = (addr_t)API_VmmIoRemapNocache((PVOID)ulPhyBase, ulAcpiSize); if (ulVirBase) { return (VOID *)(ulVirBase + ulOffset); } else { return (VOID *)(LW_NULL); }}2.2 HPET设备的注册
HPET设备的注册如程序清单2.3所示。
程序清单2.3 HPET设备的注册
INT __hpetRegister (VOID){ INT iDrvNum = iosDrvInstallEx(&__GtimerOps);/* 安装驱动程序*/return (iosDevAdd(&__GtimerDevHdr, "/dev/timer", iDrvNum)); /* 创建timer设备*/}
其中__GtimerOps即为HPET字符设备对应的操作函数集。具体内容如程序清单 2.4所示。
程序清单2.4 HPET字符设备操作函数集
struct file_operations __GtimerOps = { .fo_open = __hpetOpen, .fo_close = __hpetClose, .fo_ioctl = __hpetIoctl};
这里只实现了fo_open、fo_close和fo_ioctl这三个字符设备相关操作函数。
2.2.1 HPET设备的操作函数集1. 打开操作
HPET设备的打开操作函数实现如程序清单 2.5所示。
程序清单2.5 fo_open实现
static LONG __hpetOpen(PLW_DEV_HDR pdevhdrHdr, PCHAR pcName, INT iFlag, INT iMode){ __GobSem = API_SemaphoreBCreate("wait_timer", 0, LW_OPTION_OBJECT_GLOBAL, LW_NULL);/* 创建二进制型信号量 */ LW_DEV_INC_USE_COUNT(pdevhdrHdr);/* 增加使用计数 */ return ((LONG)pdevhdrHdr);}
2. 关闭操作
HPET设备的关闭操作函数实现如程序清单 2.6所示。
程序清单2.6 fo_close实现
static INT __hpetClose(PLW_DEV_HDR pdevhdrHdr){ if (pdevhdrHdr) { LW_DEV_INC_USE_COUNT(pdevhdrHdr);/* 减少使用计数 */ hpetTimerStop(); API_SemaphoreBDelete(&__GobSem); return (ERROR_NONE); } else { return (PX_ERROR); }}3. ioctl的实现
HPET设备的ioctl函数的实现如程序清单 2.7所示。
程序清单2.7 fo_ioctl实现static INT __hpetIoctl (PLW_DEV_HDR pdevhdrHdr, INT iCmd, LONG lArg){ hard_timer * ht; ht = (hard_timer *)lArg; switch (iCmd) { case SET_DELAY:/* 设置延时时间(ns) */ ht->iStatus = FALSE; __GuiIncrementValue = ht->ptvPeriod->tv_nsec / NSEC_PER_COUNT; hpetCounterSet(__GuiIncrementValue); break; case START_DELAY:/* 开始延时时间(ns) */ if (FALSE == ht->iStatus) { hpetTimerStart(); ht->iStatus = TRUE; } API_SemaphoreBPend(__GobSem, LW_OPTION_WAIT_INFINITE); break; default: break; } return ERROR_NONE;}
ioctl里主要调用了HPET定时器的开始与停止以及定时器计数值的设置相关函数。
定时器开始的函数实现如程序清单 2.8所示。
程序清单2.8 开始定时器工作VOID hpetTimerStart(VOID){ UINT32 ulhpetTimerCfg; API_InterVectorEnable(__Gvector); /* 使能中断*/ ulhpetTimerCfg = read32(HPET_TIMER_CONFIG_LO(2)); write32(ulhpetTimerCfg | (1 <<2 ), HPET_TIMER_CONFIG_LO(2));/* 使能HPET timer2中断*/}
定时器停止的函数实现如程序清单 2.9所示。
程序清单2.9 停止定时器工作VOID hpetTimerStop(VOID){ UINT32 ulhpetTimerCfg; ulhpetTimerCfg = read32(HPET_TIMER_CONFIG_LO(2)); write32(ulhpetTimerCfg & (~(1 <<2 )), HPET_TIMER_CONFIG_LO(2));/* 禁止HPET timer2中断 */ API_InterVectorDisable(__Gvector);/* 禁止中断 */}
定时器计数值设置的函数实现如程序清单 2.10所示。
程序清单2.10 定时器数值设置
VOID hpetCounterSet(UINT32 uiCount){ UINT32 ulcountLowVal; UINT32 ulcountHighVal; UINT32 ulcountSum; ulcountLowVal = readl(HPET_COUNTER_LO);/* 获取当前counter低32位值*/ ulcountHighVal = readl(HPET_COUNTER_HI);/* 获取当前counter高32位值*/ ulcountSum = ulcountLowVal + uiCount; if(ulcountSum < ulcountLowVal) { ulcountHighVal += 1;/* 若低32位溢出,则高32位进1*/ } /* * 设置timer2比较值寄存器 */ writel(ulcountSum, HPET_TIMER_COMPARATOR_LO(2)); writel(ulcountHighVal, HPET_TIMER_COMPARATOR_HI(2));}2.3 HPET设备的注销
HPET设备的注销如程序清单 2.11所示。
程序清单2.11 HPET设备的注销
INT __hpetUnregister(VOID){ PLW_DEV_HDR pDev; pDev = &__GtimerDevHdr; if (pDev) { /* * 卸载timer设备和驱动程序 */ iosDevDelete(pDev); return (iosDrvRemove(pDev->DEVHDR_usDrvNum, 0)); } else { return (PX_ERROR); }}2.4 HPET中断服务函数
HPET中断服务函数实现如程序清单 2.12所示。
程序清单2.12 HPET中断服务函数static irqreturn_t __tickHpetIsr (VOID){ API_SemaphoreBPost(__GobSem); hpetCounterSet(__GuiIncrementValue);/* 设置counter计数值*/ hpetTimerStart();/* 开始定时器工作计时*/ return (LW_IRQ_HANDLED);}2.5 HPET模块加载
HPET模块加载实现如程序清单 2.13所示。
程序清单2.13 HPET模块加载int module_init (void){ LW_CLASS_CPUSET cpuset; /* * 初始化hpet timer */ bspHpetTimerInit(_G_pAcpiHpet, &__Gvector);/* 定时器初始化*/ API_InterVectorConnect(__Gvector,/* 连接中断*/ (PINT_SVR_ROUTINE)__tickHpetIsr, LW_NULL, "hpetIsr"); API_InterVectorEnable(__Gvector);/* 使能中断*/ /* * 绑定定时器中断到cpu1 */ LW_CPU_ZERO(&cpuset); LW_CPU_SET(1, &cpuset); API_InterSetTarget(__Gvector, sizeof(LW_CLASS_CPUSET), &cpuset); __hpetRegister();/* timer设备注册*/ return 0;}2.6 HPET模块卸载
HPET模块卸载实现如程序清单 2.14所示。
程序清单2.14 HPET模块卸载void module_exit (void){ hpetTimerStop();/* 停止timer*/ API_InterVectorDisconnect(__Gvector, (PINT_SVR_ROUTINE)__tickHpetIsr, LW_NULL); API_InterVectorDisable(__Gvector); __hpetUnregister();/* timer设备注销*/}
- SylixOS中APIC HPET定时器字符驱动实现
- SylixOS中EEPROM设备驱动实现
- SylixOS字符设备驱动框架
- SylixOS中SD驱动实现流程(标准控制器)
- SylixOS网卡驱动实现篇
- SylixOS中RTC设备驱动
- [OSDEV]编程高精度定时器(HPET)
- 字符设备驱动--定时器
- 字符设备驱动-定时器
- SylixOS中AHCI驱动框架分析
- SylixOS中视频播放的实现
- 2410定时器驱动实现
- SylixOS的BSP开发实例之S3C2416 【第六篇】S3C2416 驱动之定时器
- SylixOS网卡驱动框架
- SylixOS网卡驱动浅析
- SylixOS音频驱动移植
- SylixOS网卡驱动优化
- APIC
- 从参与者到跻身第一梯队:中国开源云计算的崛起
- 常见的代码规范
- myeclipse添加新tomcat
- 派生类的派生类中(override)的表现
- Go 深度好文汇总
- SylixOS中APIC HPET定时器字符驱动实现
- ubuntu14.04设置默认用户为root
- 够励志!困难也是生产力
- JPress 部署教程
- 利用fastjson将map数据封装到对象中
- 库房管理系统之遮罩锁屏
- NDK开发之------Error: Flag android.useDeprecatedNdk is no longer supported爬坑
- SAP创建物料主数据(维护长文本,质量视图中质量类型,分类视图)
- 如何使用RedisTemplate访问Redis数据结构