SylixOS中APIC HPET定时器字符驱动实现
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 x86 HPET 定时器驱动
HPET(High Precision Event Timer) 俗称高精度定时器,最低时钟频率为10MHZ,而且定义了比较严格的精确度(间隔 >= 1 毫秒的允许 +-0.05% 的误差,间隔 ...
- 关于linux字符驱动中read函数filp->f_pos 和 loff_t *ppos的关系
在学习linux 字符驱动的时候会有这样的困惑 比如我们实现一个字符驱动的读函数,如下 static ssize_t globalmem_read(struct file *filp, char __ ...
- Linux字符驱动开发学习总结
linux驱动编写(虚拟字符设备编写) 昨天我们说了一些简单模块编写方法,但是终归没有涉及到设备的编写内容,今天我们就可以了解一下相关方面的内容,并且用一个实例来说明在linux上面设备是如何编写的. ...
- kernel 自定义字符驱动 第一次实验
第一次创建哈, Oh yeach 用了一个字符驱动的模板哈,第二次就可以正常了 第二次的结果就好的多, 但是也说明 系统调用 只要系统退出 都会 调用 字符设备的 release api FpgaRe ...
- linux2.6驱动学习笔记之字符驱动
1.字符驱动组成 1.1字符驱动的模块加载与卸载 //设备结构体模板 struct xxx_dev_t { struct cdev cdev; ...... }xxx_dev; 在字符驱动模块加载函数 ...
- 详解Linux2.6内核中基于platform机制的驱动模型
原文地址:详解Linux2.6内核中基于platform机制的驱动模型 作者:nacichan [摘要]本文以Linux 2.6.25 内核为例,分析了基于platform总线的驱动模型.首先介绍了P ...
- 基于OMAPL138的字符驱动_GPIO驱动AD9833(三)之中断申请IRQ
基于OMAPL138的字符驱动_GPIO驱动AD9833(三)之中断申请IRQ 0. 导语 学习进入到了下一个阶段,还是以AD9833为例,这次学习是向设备申请中断,实现触发,在未来很多场景,比如做用 ...
- SylixOS下基于NUC970的NAND驱动
开发环境 开发环境 宿主机: Windows7 64bits 系统 开发板: 安米MDK972 软件环境: RealEvo-IDE3.0 NAND Flash: S34ML02G100TF100 S3 ...
- SylixOS中select原理及使用分析
2019独角兽企业重金招聘Python工程师标准>>> 1. select接口简介 1.1 select接口使用用例 select是操作系统多路I/O复用技术实现的方式之一. 多路I ...
最新文章
- Activity与Fragment的生命周期详解
- python中文文本分析_python--文本分析
- 红橙Darren视频笔记 圆点loadingView 动画ANR
- curl post请求 header host_(科普文)curl quot;可quot;得一切
- Windows10桌面美化
- 利用格拉布斯准则,剔除异常数据
- 莫以物喜 -=莫以己悲!
- Android黄油刀插件使用记录
- 大数据开发中HBase高级特性和rowkey设计分析
- DRV8818步进电机一种应用场景及实现思路
- file 转换MultipartFile
- 基于OP放大器的有源模拟滤波器设计--基础知识
- 存储系统中的算法:LSM 树设计原理
- P6-Windows与网络基础-安装eNSP软件环境
- 关于MySQL的版本
- 小熊派4G开发板初体验SDK开发
- Anycodes,在线编程网站上线啦!支持六种编程语言,语法高亮,行数显示,和代码自动折叠。小伙伴们,请速度围观!
- 433M无限遥控发射与接收
- 可牛影像全新拍照功能使用教程
- canon 打印机 android,Canon PRINT Inkjet/SELPHY
热门文章
- python有趣小程序春节祝福-教你用python群发微信新年祝福
- 在360新员工入职培训上的讲话
- 国内外vps有什么区别?
- 2019TFE计算机科学排名,美国留学|2019TFE Times 硕士专业排名
- (文末送书)字符数组与字符串
- 打造老年人的健康监测产品很有市场(随记)
- EtherNet/IP协议开发2:理论学习
- cobar mysql部署方案_Cobar的安装和配置步骤
- 编译-POCO C++支持iOS平台的静态库
- 2019 siggraph_观看SIGGRAPH 2019的Unity图形会议