7.阻塞型驱动设计

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了7.阻塞型驱动设计相关的知识,希望对你有一定的参考价值。

阻塞型驱动设计

技术分享

技术分享

技术分享

技术分享

技术分享

 

技术分享

技术分享

唤醒之后按优先级执行。

对按键驱动进行阻塞型改造

改造的duokey.c:

Make会产生一下的问题还没解决,由于没有网络。差个头文件.....

技术分享

明天有网络再说咯

找到了头文件,linux/sched.h又出现了奇怪的错误:

技术分享

很奇怪,是重名。可我没有定义key..h,是系统的。最后改为button_init和button_exit.make通过了。

Duokey.c的代码:

 

#include <linux/module.h>        /* For module specific items */

#include <linux/fs.h>            /* For file operations */

#include <linux/ioport.h>        /* For io-port access */

#include <linux/io.h>            /* For inb/outb/... */

#include <linux/init.h>

#include <linux/miscdevice.h>

#include <linux/interrupt.h>

#include <linux/slab.h>

#include <linux/uaccess.h>

#include <linux/sched.h>

#define TASK_UNINTERRUPTIBLE    2

#define TASK_INTERRUPTIBLE    1

#define TASK_NORMAL        (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)

#define GPNCON 0x7f008830

#define GPNDAT 0x7f008834

 

 

struct work_struct *work1;

struct timer_list key_timer;//定义定时器

unsigned int *gpio_data;

 

//全局变量,初始化为0

unsigned int key_num =0 ;

//定义等待队列

wait_queue_head_t key_q;

//read按键

ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)

{

    wait_event(key_q,key_num);

    printk("<0> in kernel:key num is%d\n",key_num);

    //返回内核的给用户

    copy_to_user(buf,&key_num,4);

    key_num=0;//清空按键

    return 4;

}

 

void work1_func(struct work_struct *work)

{

    //启动定时器 100毫秒超时=HZ/10,HZ=1秒。jiffies是系统当前时间

    mod_timer(&key_timer,jiffies+HZ/10);

}

void key_timer_func(unsigned long data)

{    //定时器超时的函数需要修改,需要判断是哪个按键超时

    

    unsigned int key_val;

    //超时的时候,就要读取data

    key_val=readw(gpio_data)&0x01;//读出一个按键EINT0的值。

    //当他被按下,就是低电平的时候,就是被按下了。才是有效的按键

    if(0==key_val)//真正按下

        key_num=1;//读取按键编号

 

    key_val=readw(gpio_data)&0x02;//读出一个按键EINT1的值。

    //当他被按下,就是低电平的时候,就是被按下了。才是有效的按键

    if(0==key_val)//真正按下

        key_num=2;

    

    //当有数据的时候,需要唤醒

    wake_up(&key_q);

}

 

irqreturn_t key_int(int irq, void *dev_id)

{

    //1.检测是否发生了按键中断

    //2.清除已经发生的按键中断

//前面的都是硬件相关的工作,必须在中断里面执行

//下面是硬件无关的工作,我们把它提到中断以外的work1_func函数去处理。

    //3.打印按键值

    schedule_work(work1);

    

    return 0;

}

 

void key_hw_init()

{

    unsigned int *gpio_config;

    unsigned short data;

    gpio_config = ioremap(GPNCON,4);

    data = readw(gpio_config);

    data &= ~0b1111;//增加一个按键

    data |= 0b1010;

    writew(data,gpio_config);

 

    gpio_data = ioremap(GPNDAT,4);

}

int key_open(struct inode *node, struct file *filp)

{

    return 0;

}

struct file_operations key_fops =

{

    .open = key_open,

    .read = key_read,//增加了读取操作

};

struct miscdevice key_miscdevice =

{

    .minor = 200,

    .name = "6410key",

    .fops = &key_fops,

};

 

static int button_init()

{

    misc_register(&key_miscdevice);

    //注册中断处理程序

    request_irq(IRQ_EINT(0),key_int, IRQF_TRIGGER_FALLING,"6410key",0);

    //增加一个按键的支持

    request_irq(IRQ_EINT(1),key_int, IRQF_TRIGGER_FALLING,"6410key",0);

    

    //硬件初始化

    key_hw_init();//相应的位进行设置

 

    //2. 创建工作

    work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);

    INIT_WORK(work1, work1_func);

    //定时器初始化

    init_timer(&key_timer);

    key_timer.function=key_timer_func;

    

    //注册定时器

    add_timer(&key_timer);

 

    //初始化等待队列

    init_waitqueue_head(&key_q);

    return 0;

}

 

static void button_exit()

{

    misc_deregister(&key_miscdevice);

    

}

 

module_init(button_init);

module_exit(button_exit);

 

/*优化:多一个中断,gpio也进行多按键初始化,中断产生的时候要判断是哪个按键产生的中断。*/

Make成功:

技术分享

以上是关于7.阻塞型驱动设计的主要内容,如果未能解决你的问题,请参考以下文章

linux设备驱动归纳总结:5.阻塞型IO实现

linux驱动开发学习二:创建一个阻塞型的字符设备

linux驱动编写之阻塞与非阻塞

网络I/O模型

nginx

Linux设备驱动程序 之 异步通知