linux设备驱动的周期事件
带有定时器/线程的周期事件的驱动结构与带有中断的驱动程序结构类似,只是把其中的中断处理函数换成定时器或线程处理函数,其模型如下图所示。
周期性事件处理有两种:定时器和线程。 使用定时器处理周期性事件 #include <linux/timer.h> 定义定时器 struct timer_list { struct list_head list; // 用来形成链表,由内核管理
unsigned long expires; // 定时器到期时间,jiffies,HZ
unsigned long data; // 作为参数被传入定时器处理函数
void (*function)(unsigned long);// 定时器处理函数
}; 初始化定时器,实质是把链表的头尾置空 void init_timer(struct timer_list *timer); 添加定时器 void add_timer(struct timer_list * timer); 删除定时器 int del_timer(struct timer_list * timer); 定时器示例 struct timer_list myTimer; init_timer(&myTimer); //jiffies,内核的全局变量,系统定时
myTimer.expires = jiffies + 3 * HZ; //expires只执行一次,HZ 代表秒
myTimer.data = 0L; myTimer.function = timerHandler; //定时到,处理的函数
add_timer(&myTimer); //添加到定时链表中
定时器处理函数 void timerHandler(unsigned long data) { // 如需重复执行, 需要重新初始化并启动定时器
myTimer.expires = jiffies + 3 * HZ; add_timer(&myTimer); } 退出时一定要删除定时器,否则系统崩溃 del_timer(myTimer); 使用内核线程处理周期性事件,这与普通的线程的使用方法基本一样 #include <linux/kernel.h> 创建内核线程,设置 flags线程的属性 pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); 实例: kernel_thread(thread_function, (void*)thread_data, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); 设置延时 set_current_state(TASK_UNINTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ * 5); 注意:模块退出时必须等待线程退出 schedule() // 让出调度器
以下以定时器的周期事件为例。实验平台:凌阳SPCE3200 实验箱,对应的硬件设备为pod。硬件连接:把JP32所有管脚短接。整个驱动分为三个模块:获得pod键值的模块Pod_Drv.c、FIFO队列的模块/kernel/kerne/kfifo.c 、真正的pod驱动模块pod.c。这样,在加载pod驱动时必先要加载kfifo.o和Pod_Drv.o模块。 /kernel/kerne/kfifo.c为内核中的函数模块,直接编译就能使用。 Pod_Drv.c为自己写的模块,该模块有三个文件:POD_Config.h配置头文件、Pod_Drv.h对应Pod_Drv.c的头文件、Pod_Drv.c。具体代码如下: //POD_Config.h
#ifndef _POD_CONFIG_H_ #define _POD_CONFIG_H_
#include <asm/arch/S3C2410.h> #define P_POD_GPIO_OE GPFCON // GPxCON寄存器
#define P_POD_GPIO_OUTPUT GPFDAT // GPxDAT寄存器
#define P_POD_GPIO_PULLUP GPFUP // GPxUP寄存器
#define P_POD_GPIO_INPUT GPFDAT // GPxDAT寄存器
#define POD_RDY_BIT 5 // RDY位
#define POD_CLK_BIT 4 // CLK位
#define POD_MISO_BIT 3 // MISO位
#define POD_MOSI_BIT 2 // MOSI位
#define POD_SS_BIT 1 // SS位
#define POD_CHG_BIT 0 // Change位
#define POD_RDY_Get() ( (P_POD_GPIO_INPUT & (0x00000001<<POD_RDY_BIT) ) ? 1 : 0 ) #define POD_CHG_Get() ( (P_POD_GPIO_INPUT & (0x00000001<<POD_CHG_BIT) ) ? 1 : 0 )
#define POD_CLK_Set() ( P_POD_GPIO_OUTPUT |= (0x00000001<<POD_CLK_BIT))
#define POD_CLK_Clr() (P_POD_GPIO_OUTPUT &= ~(0x00000001<<POD_CLK_BIT))
#define POD_MISO_Get() ((P_POD_GPIO_INPUT & (0x00000001<<POD_MISO_BIT))?1:0)
#define POD_MOSI_Set() (P_POD_GPIO_OUTPUT |= (0x00000001<<POD_MOSI_BIT))
#define POD_MOSI_Clr() (P_POD_GPIO_OUTPUT &= ~(0x00000001<<POD_MOSI_BIT))
#define POD_SS_Set() (P_POD_GPIO_OUTPUT |= (0x00000001<<POD_SS_BIT))
#define POD_SS_Clr() (P_POD_GPIO_OUTPUT &= ~(0x00000001<<POD_SS_BIT))
#endif //Pod_Drv.h
#ifndef _POD_DRV_H_ #define _POD_DRV_H_
#include "POD_Config.h"
extern void POD_Init(void); extern void POD_SetAKS(unsigned char AKS_Code); extern void POD_SetPowerMode(unsigned char PWR_Code); extern void POD_SetResolution(unsigned char RESL_Code); extern short POD_Get(unsigned char *pKeyCode, unsigned char *pWheelCode);
#define POD_AKS_DIS 0x00 #define POD_AKS_GLOBAL 0x01 #define POD_AKS_KEY_WHEEL 0x02 #define POD_AKS_4KEY_3KEY_WHEEL 0x03 #define POD_AKS_4KEY_OTHER 0x04 #define POD_AKS_KEY7_OTHER 0x05 #define POD_PWR_FULL 0x00 #define POD_PWR_MODE1 0x09 #define POD_PWR_MODE2 0x0A #define POD_PWR_MODE3 0x0B #define POD_PWR_MODE4 0x0C #define POD_PWR_SYNC 0x0D #define POD_PWR_SLEEP 0x0E #define POD_RESL_4 0x20 #define POD_RESL_8 0x40 #define POD_RESL_16 0x60 #define POD_RESL_32 0x80 #define POD_RESL_64 0xA0 #define POD_RESL_128 0xC0 #define POD_RESL_256 0xE0 #define POD_STATUS_CHANGED 1 #define POD_STATUS_NOCHANGE 0 #define POD_STATUS_BUSY -1 #endif // Pod_Drv.c
//=================================================================
//文 件 名:POD_Drv.c
//功能描述: POD驱动程序
//=====================================================================
#include <linux/module.h> #include <linux/slab.h> #include "Pod_Drv.h"
static unsigned char POD_CmdBytes[3]; //=============================================================
//语法格式: void POD_Delay10us(unsigned int Length);
//实现功能: (内部调用)延时
//参数: Length: 延时长度,单位10us
//返回值: 无
//=============================================================
void POD_Delay10us(unsigned int Length) { unsigned int i; while(Length--) { for(i=0;i<0x2A;i++) { __asm("nop"); __asm("nop"); } } }
//=============================================================
//语法格式: unsigned char POD_SPI(unsigned char Data);
//实现功能: (内部调用)模拟SPI时序收发数据,上升沿准备好待发送数据,下降沿进行数据交换
//参数: Data: 待发送的字节
//返回值: 接收到的字节
//=============================================================
unsigned char POD_SPI(unsigned char Data) { unsigned char Mask, i, Ret; Mask = 0x80; Ret = 0x00; POD_SS_Clr(); POD_Delay10us(2); for(i=0; i<8; i++) { if((Data&Mask)==0) //从最高位开始发送数据
POD_MOSI_Clr(); //最高位是0,准备好数据0
else POD_MOSI_Set(); //最高位是1,准备好数据1
POD_CLK_Clr(); //下降沿交换数据
POD_Delay10us(2); if(POD_MISO_Get()!=0) //根据MISO信号,决定接收的数据是1还是0
Ret |= Mask; POD_CLK_Set(); POD_Delay10us(2); Mask >>= 1; } POD_SS_Set(); POD_Delay10us(2); return Ret; } //=============================================================
//语法格式: short POD_IsKeyChanged(void);
//实现功能: (内部调用)查询SPI通讯是否准备好
//参数: 无
//返回值: 0: 未准备好 1: 已准备好
//=============================================================
static short POD_IsReady(void) { return POD_RDY_Get(); } //=============================================================
//语法格式: short POD_IsKeyChanged(void);
//实现功能: 查询按键和滑轮状态是否发生了变化
//参数: 无
//返回值: 0: 无变化 1: 发生了变化
//=============================================================
static short POD_IsKeyChanged(void) { return POD_CHG_Get(); } //=============================================================
//语法格式: void POD_Init(void);
//实现功能: POD初始化
//参数: 无
//返回值: 无
//=============================================================
void POD_Init(void) { // RDY, MISO, CHG上拉失能,初始化为输入
//MISI,nSS,clk 上拉使能,初始化为输出
P_POD_GPIO_PULLUP |= ((0x01<<POD_RDY_BIT) + (0x01<<POD_MISO_BIT) + (0x01<<POD_CHG_BIT)); P_POD_GPIO_OE &= ~((0x03 << (POD_RDY_BIT << 1)) | (0x03 << (POD_CLK_BIT << 1)) | (0x03 << (POD_MISO_BIT << 1)) | (0x03 << (POD_MOSI_BIT << 1)) | (0x03 << (POD_SS_BIT << 1)) | (0x03 << (POD_CHG_BIT << 1))); P_POD_GPIO_OE |=((0x01 << (POD_CLK_BIT << 1)) + (0x01 << (POD_MOSI_BIT << 1)) + (0x01 << (POD_SS_BIT << 1))); POD_SS_Set(); POD_CLK_Set(); POD_CmdBytes[0] = POD_AKS_GLOBAL; POD_CmdBytes[1] = 0x10 | POD_PWR_FULL; POD_CmdBytes[2] = POD_RESL_128; while(!POD_IsReady()); POD_SPI(POD_CmdBytes[0]); POD_SPI(POD_CmdBytes[1]); POD_SPI(POD_CmdBytes[2]); } EXPORT_SYMBOL(POD_Init); //=============================================================
//语法格式: void POD_SetAKS(unsigned char AKS_Code);
//实现功能: 设定AKS(Adjacent Key Suppression, 邻键抑制)模式
//参数: AKS_Code: POD_AKS_DIS - 关闭AKS功能
//POD_AKS_GLOBAL - 所有键、滑轮轮互斥
//POD_AKS_KEY_WHEEL - 键与滑轮轮二者互斥
// POD_AKS_4KEY_3KEY_WHEEL - Key1~4、Key5~7、滑轮三者互斥
//POD_AKS_4KEY_OTHER - Key1~4与(Key5~7 + 滑轮)二者互斥
// POD_AKS_KEY7_OTHER - Key7与(Key1~6 + 滑轮)二者互斥
//返回值: 无
//=============================================================
void POD_SetAKS(unsigned char AKS_Code) { POD_CmdBytes[0] &= ~0x0F; POD_CmdBytes[0] |= AKS_Code&0x0F; } //=============================================================
//语法格式: void POD_SetPowerMode(unsigned char PWR_Code);
//实现功能: 设定电源模式
//参数: PWR_Code: POD_PWR_FULL - 全速运行
// POD_PWR_MODE1 - 省电模式1,响应时间200ms
// POD_PWR_MODE2 - 省电模式2,响应时间280ms
// POD_PWR_MODE3 - 省电模式3,响应时间440ms
// POD_PWR_MODE4 - 省电模式4,响应时间760ms
// POD_PWR_SYNC - 同步模式
// POD_PWR_SLEEP - 睡眠模式
//返回值: 无
//=============================================================
void POD_SetPowerMode(unsigned char PWR_Code) { POD_CmdBytes[1] &= ~0x07; POD_CmdBytes[1] |= PWR_Code&0x07; } //=============================================================
//语法格式: void POD_SetResolution(unsigned char RESL_Code);
//实现功能: 设定滑轮的分辨率(区域数量)
//参数: RESL_Code: POD_RESL_4 - 4个区域
// POD_RESL_8 - 8个区域
// POD_RESL_16 - 16个区域
// POD_RESL_32 - 32个区域
// POD_RESL_64 - 64个区域
// POD_RESL_128 - 128个区域
// POD_RESL_256 - 256个区域
//返回值: 无
//=============================================================
void POD_SetResolution(unsigned char RESL_Code) { POD_CmdBytes[2] &= ~0xE0; POD_CmdBytes[1] |= RESL_Code&0xE0; } //=============================================================
//语法格式: short POD_Get(unsigned char *pKeyCode, unsigned char *pWheelCode);
//实现功能: 获取POD键值
//参数: pKeyCode: 存储Key值的地址,Key值结构为:
// bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
// 滑轮 Key7 Key6 Key5 Key4 Key3 Key2 Key1
// pWheelCode: 存储滑轮位置的地址
// 返回值: POD状态: POD_STATUS_CHANGED - 按键或滑轮状态发生过改变
// POD_STATUS_NOCHANGE - 按键或滑轮状态未发生改变
// POD_STATUS_BUSY - 未准备好,获取键值失败
//=============================================================
short POD_Get(unsigned char *pKeyCode, unsigned char *pWheelCode) { short Ret = 0; if(POD_IsKeyChanged()) Ret = 1; if(!POD_IsReady()) Ret = -1; else { POD_SPI(POD_CmdBytes[0]); *pKeyCode = POD_SPI(POD_CmdBytes[1]); *pWheelCode = POD_SPI(POD_CmdBytes[2]); } return Ret; } EXPORT_SYMBOL(POD_Get);
注意: 1、该模块的void POD_Init(void) 与short POD_Get(unsigned char *pKeyCode, unsigned char *pWheelCode)函数是要被内核态下的pod驱动调用的,所以要把他们设成全局的,方法就是在该函数之后加上一句EXPORT_SYMBOL(函数名);否则,pod驱动是无法调用该模块下的函数的。
2、该模块的编译与编译/kernel/kerne/kfifo.c 的方法类似: /usr/local/arm/2.95.3/bin/arm-linux-gcc -c -o Pod_Drv.o Pod_Drv.c -I/root/kernel/include -D__KERNEL__ -DMODULE -DEXPORT_SYMTAB -DMODVERSIONS //驱动pod.c
#ifndef __KERNEL__ #define __KERNEL__ #endif #ifndef MODULE #define MODULE #endif
#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> /* printk() */ #include <linux/init.h> /* __init __exit */ #include <linux/types.h> /* size_t */ #include <linux/fs.h> /* file_operation */ //#include /* Error number */
#include <linux/delay.h> /* udelay */ //#include
#include <asm/uaccess.h> /* copy_to_user, copy_from_user */ #include <asm/hardware.h> #include <asm/semaphore.h> #include <asm/irq.h> #include <asm/arch/S3C2410.h> #include <linux/kfifo.h> #include "Pod_Drv.h"
#define DRIVER_NAME "pod" #ifdef DEBUG #define PRINTK(fmt, arg...) printk(KERN_NOTICE fmt, ##arg) #else #define PRINTK(fmt, arg...) #endif #define BUFFER_SIZE 256 #define FREQ HZ/60
static int podDriver_Major = 0; /* Driver Major Number */ struct semaphore bufflock; static spinlock_t buffer_lock = SPIN_LOCK_UNLOCKED; static struct kfifo *buffer; static struct timer_list timer; static unsigned char keyBuf[2]; static unsigned char Key, Wheel; static void timer_callback(unsigned long data) { if(POD_Get(&Key, &Wheel) == POD_STATUS_CHANGED) { keyBuf[0] = Key; keyBuf[1] = Wheel; kfifo_put(buffer, keyBuf, sizeof(keyBuf)); up(&bufflock); // PRINTK("key = 0x%x, Wheel = 0x%x", Key, Wheel);
} /* Set timer again */ // PRINTK("timer_callback\n");
timer.expires = jiffies + FREQ; add_timer(&timer); } /* Driver Operation Functions */ static int podDriver_open(struct inode *inode, struct file *filp) { MOD_INC_USE_COUNT; PRINTK("podDriver open called!\n"); POD_Init(); sema_init(&bufflock, 0); buffer = kfifo_alloc(BUFFER_SIZE, GFP_KERNEL, &buffer_lock); add_timer(&timer); return 0; } static int podDriver_release(struct inode *inode, struct file *filp) { MOD_DEC_USE_COUNT; PRINTK("podDriver release called!\n"); kfifo_free(buffer); del_timer(&timer); return 0; } static ssize_t podDriver_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) { size_t read_size = count; // PRINTK("myDriver read called!\n");
down_interruptible(&bufflock); kfifo_get(buffer, keyBuf, sizeof(keyBuf)); copy_to_user(buf, &keyBuf, read_size); return read_size; } static struct file_operations podDriver_fops = { owner: THIS_MODULE, // write: podDriver_write,
read: podDriver_read, // ioctl: podDriver_ioctl,
open: podDriver_open, release: podDriver_release, }; #ifdef CONFIG_DEVFS_FS devfs_handle_t devfs_podDriver_dir; devfs_handle_t devfs_podDriver_raw; #endif static int __init myModule_init(void) { init_timer(&timer); timer.expires = jiffies + FREQ; timer.data = (unsigned long)0; timer.function = &timer_callback; /* Module init code */ PRINTK("myModule_init\n"); /* Driver register */ podDriver_Major = register_chrdev(0, DRIVER_NAME, &podDriver_fops); if(podDriver_Major < 0) { PRINTK("register char device fail!\n"); return podDriver_Major; } PRINTK("register podDriver OK! Major = %d\n", podDriver_Major); #ifdef CONFIG_DEVFS_FS devfs_podDriver_dir = devfs_mk_dir(NULL, "podDriver", NULL); devfs_podDriver_raw = devfs_register(devfs_podDriver_dir, "raw0", DEVFS_FL_DEFAULT, podDriver_Major, 0, S_IFCHR | S_IRUSR | S_IWUSR, &podDriver_fops, NULL); PRINTK("add dev file to devfs OK!\n"); #endif return 0; } static void __exit myModule_exit(void) { /* Module exit code */ PRINTK("myModule_exit\n"); /* Driver unregister */ if(podDriver_Major > 0) { #ifdef CONFIG_DEVFS_FS devfs_unregister(devfs_podDriver_raw); devfs_unregister(devfs_podDriver_dir); #endif unregister_chrdev(podDriver_Major, DRIVER_NAME); } return; } MODULE_AUTHOR("SXZ"); MODULE_LICENSE("Dual BSD/GPL"); module_init(myModule_init); module_exit(myModule_exit); //对应的测试应用程序pod_test.c
#include <stdio.h> #include <fcntl.h> #include <unistd.h> int main(int argc, char *argv[]) { int fd; unsigned char keyBuf[2]; unsigned char p_key, p_wheel; if((fd = open("/dev/podDriver/raw0", O_RDONLY)) < 0) { printf("can't open podDriver\n"); exit(1); } while(1) { read(fd, &keyBuf, 2); p_key = keyBuf[0]; p_wheel = keyBuf[1]; printf("\n p_key = %d, p_wheel = %d\n", p_key, p_wheel); } close(fd); return 0; }
注:小志整理
|