Chinaunix首页 | 论坛 | 博客
  • 博客访问: 612500
  • 博文数量: 144
  • 博客积分: 5037
  • 博客等级: 大校
  • 技术积分: 1581
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-30 21:49
文章存档

2010年(16)

2009年(128)

分类: LINUX

2009-06-21 14:44:51

 

          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;
}

注:小志整理

阅读(1082) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~