带有定时器/线程的周期事件的驱动结构与带有中断的驱动程序结构类似,只是把其中的中断处理函数换成定时器或线程处理函数,其模型如下图所示。
周期性事件处理有两种:定时器和线程。
使用定时器处理周期性事件
#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 <linux/errno.h> /* Error number */
#include <linux/delay.h> /* udelay */
//#include <linux/timer.h>
#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;
}