Bootstrap

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.cFIFO队列的模块/kernel/kerne/kfifo.c 、真正的pod驱动模块pod.c。这样,在加载pod驱动时必先要加载kfifo.oPod_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~4Key5~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;

}

 

 

;