专题12-按键驱动程序设计

第1课-混杂设备驱动模型

  1. 混杂设备描述

在Linux系统中,存在一类字符设备,它们拥有相同的主设备号(10),但次设备号不同,我们称这类设备为混杂设备(miscdevice)。所有的混杂设备形成一个链表,对设备访问时内核根据混杂设备形成一个链表,对设备访问时内核根据次设备号查找到相应的混杂设备。

Linux中使用struct miscdevice来描述一个混杂设备。

struct miscdevice {

int minor; /* 次设备号*/

const char *name; /* 设备名*/

const struct file_operations *fops; /*文件操作*/

struct list_head list;

struct device *parent;

struct device *this_device;

};

  1. 混杂设备注册

Linux中使用misc_register函数来注册一个混杂设备驱动。

int misc_register(struct miscdevice * misc)。

  1. 范例分析

初始化miscdevice:minor,name,fops

注册miscdevice:misc_register

key.c

#include <linux/module.h>

#include <linux/init.h>

#include <linux/miscdevice.h>

#include <linux/interrupt.h>

#include <linux/fs.h>

#include <linux/io.h>

#define GPFCON 0x56000050

irqreturn_t key_int(int irq, void *dev_id)

{

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

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

//3. 打印按键值

printk("key down!\n");

return 0;

}

void key_hw_init()

{

unsigned short data;

unsigned int *gpio_config;

gpio_config = ioremap(GPFCON,4);

data = readw(gpio_config);

data &= ~0b11;

data |= 0b10;

writew(data,gpio_config);

}

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

{

return 0;

}

struct file_operations key_fops =

{

.open = key_open,

};

struct miscdevice key_miscdev = {

.minor = 200,

.name = "tq2440key",

.fops = &key_fops,

};

static int button_init()

{

misc_register(&key_miscdev);

//按键硬件初始化

key_hw_init();

//注册中断处理程序

request_irq(IRQ_EINT0,key_int,IRQF_TRIGGER_FALLING,"tq2440key",0);

return 0;

}

static void button_exit()

{

misc_deregister(&key_miscdev);

}

module_init(button_init);

module_exit(button_exit);

第2课-Linux中断处理

  1. 逻辑中断处理程序回顾

中断有个统一的入口,事先要注册中断处理程序,根据中断源编号调用中断处理程序。

  1. Linux中断处理流程分析
  1. Linux中断处理程序设计

(1)       注册中断

request_irq函数用于注册中断

int request_irq(unsigned int irq,

void (*handler)(int, void*, struct

pt_regs *),

unsigned long flags,

const char *devname,

void *dev_id)

返回0表示成功,或者返回一个错误码。

unsigned int irq:中断号

v void (*handler)(int,void *):中断处理函数。

v unsigned long flags:与中断管理有关的各种选项。

v const char * devname:设备名

v void *dev_id:共享中断时使用。

在flags参数中,可以选择一些与中断管理有关的选项,如:

IRQF_DISABLED(SA_INTERRUPT)

如果设置该位,表示是一个“快速”中断处理程序;如果没有设置这位,那么是一个“慢速”中断处理程序。

IRQF_SHARED(SA_SHIRQ)

该位表明该中断号是多个设备共享的。

快/慢速中断的主要区别在于:快速中断保证中断处理的原子性(不被打断),而慢速中断则不保证。换句话说,也就是“开启中断”标志位(处理器IF)在运行快速中断处理程序时是关闭的,因此在服务该中断时,不会被其他类型的中断打断;而调用慢速中断处理时,其它类型的中断仍可以得到服务。

(2)       中断处理

中断处理程序的特别之处是在中断上下文中运行的,它的行为受到某些限制:不能使用可能引起阻塞的函数;不能使用可能引起调度的函数。

检查设备是否产生了中断,清除中断产生标志,相应的硬件操作。

(3)       注销处理

当设备不再需要使用中断时(通常在驱动卸载时), 应当把它们注销, 使用函数:

void free_irq(unsigned int irq, void *dev_id)

(4)程序

第3课-按键驱动硬件操作实现

第4课-中断分层处理

  1. 中断嵌套
  1. 中断分层处理

上半部:当中断发生,它进行相应地硬件读写,并“登记”该中断。通常由中断处理程序充当上半部。

下半部:在系统空闲的时候对上半部“登记”的中断进行后续处理

(1)       软中断

(2)       tasklet

(3)       工作队列

工作队列是一种将任务推后执行的形式,他把推后的任务交由一个内核线程去执行。这

样下半部会在进程上下文执行,它允许重新调度甚至睡眠。每个被推后的任务叫做“工作”,由这些工作组成的队列称为工作队列。

l  Linux内核使用struct work_struct来描述一个工作队列:

struct workqueue_struct {

struct cpu_workqueue_struct *cpu_wq;

struct list_head list;

const char *name; /*workqueue name*/

int singlethread;

int freezeable; /* Freeze threads during suspend */

int rt;

};

l  Linux内核使用struct work_struct来描述一个工作项:

struct work_struct {

atomic_long_t data;

struct list_head entry;

work_func_t func;

};

typedef void (*work_func_t)(struct work_struct *work);

l  工作队列创建步骤:

step1. 创建工作队列

create_workqueue

step2. 创建工作

INIT_WORK

step3. 提交工作

queue_work

  1. 使用工作队列实现分层

在大多数情况下, 驱动并不需要自己建立工作队列,只需定义工作, 然后将工作提交到内核已经定义好的工作队列keventd_wq中。

提交工作到默认队列:schedule_work

第5课-按键定时器去抖

  1. 按键去抖

按键所用开关为机械弹性开关,当机械触点断开、闭合时,由于机械触点的弹性作用,开关不会马上稳定地接通或断开。因而在闭合及断开的瞬间总是伴随有一连串的抖动。

按键去抖动的方法主要有二种,一种是硬件电路去抖动;另一种就是软件延时去抖。而延

时又一般分为二种,一种是for循环等待,另一种是定时器延时。在操作系统中,由于效率方面的原因,一般不允许使用for循环来等待,只能使用定制器。

  1. 内核定时器

Linux内核使用struct timer_list来描述一个定时器:

struct timer_list {

struct list_head entry;

unsigned long expires;

void (*function)(unsigned long);

unsigned long data;

struct tvec_base *base;

};

(1)       init_timer初始化

(2)       设置超时函数

  1. add_timer注册定时器
  2. mod_timer启动定时器

第6课-驱动支持多按键优化

第7课-阻塞型驱动设计

  1. 阻塞必要性

当一个设备无法立刻满足用户的读写请求时应当如何处理? 例如:调用read时,设备没有数据提供, 但以后可能会有;或者一个进程试图向设备写入数据,但是设备暂时没有准备好接收数据。当上述情况发生的时候,驱动程序应当(缺省地)阻塞进程,使它进入等待(睡

眠)状态,直到请求可以得到满足。

2.内核等待队列

在实现阻塞驱动的过程中,也需要有一个“候车室”来安排被阻塞的进程“休息”,当唤醒它们的条件成熟时,则可以从“候车室”中将这些进程唤醒。而这个“候车室”就是等待队列。

(1)定义等待队列:wait_queue_head_t my_queue

(2)初始化等待队列:init_waitqueue_head(&my_queue)

(3)定义+初始化等待队列:DECLARE_WAIT_QUEUE_HEAD(my_queue)

(4)进入等待队列,睡眠

wait_event(queue,condition)

当condition(布尔表达式)为真时,立即返回;否则让进程进入TASK_UNINTERRUPTIBLE模式的睡眠,并挂在queue参数所指定的等待队列上。

wait_event_interruptible(queue,condition)

当condition(布尔表达式)为真时,立即返回;否则让进程进入TASK_INTERRUPTIBLE的睡眠,并挂在queue参数所指定的等待队列上。

int wait_event_killable(queue, condition)

当condition(一个布尔表达式)为真时,立即返回;否则让进程进入TASK_KILLABLE的睡眠,并挂在queue参数所指定的等待队列上。

(5)从等待队列中唤醒进程

wake_up(wait_queue_t *q)

从等待队列q中唤醒状态为TASK_UNINTERRUPTIBLE,TASK_INTERRUPTIBLE,TASK_KILLABLE 的所有进程。

wake_up_interruptible(wait_queue_t *q)

从等待队列q中唤醒状态为TASK_INTERRUPTIBLE 的进程

3. 阻塞驱动优化

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

转载于:https://www.cnblogs.com/free-1122/p/11452261.html

第四季-专题12-按键驱动程序设计相关推荐

  1. 关于《详解》第12.1节按键驱动的进一步阐述

    <详解>12.1的按键驱动,是本书的最大失误,应大家的要求,我们很有必要对其进行再次阐述.          注意标题是"按键"驱动而非"键盘"驱动 ...

  2. sm总线控制器找不到驱动程序_细说嵌入式系统下的驱动程序设计

    嵌入式系统驱动程序的开发有别于WIndows或Linux.后者除了必须了解新设备的硬件特性,把控制硬件的程序尽快完成之外,还需要设法让驱动程序符合Windows或Linux的规定(大且复杂的架构).但 ...

  3. Linux下的C编程实战(开发平台搭建,文件系统编程,进程控制与进程通信编程,“线程”控制与“线程”通信编程,驱动程序设计,专家问答)

    Linux下的C编程实战(一) ――开发平台搭建 1.引言 Linux操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越Windows的安全性和稳定性.而近年来,Linux ...

  4. WINCE 按键驱动编写

    该按键驱动摘自WINCE的FM1702读写器中的按键代码,按键中断的触发将会通过发送消息传递到标题为"FM1702测试界面[wenziqi@hotmail.com]"的对话框中. ...

  5. 简单说说驱动程序设计的入门

    简单说说驱动程序设计的入门,其实初级驱动设计中也能使用C++,也能使用类,但和用户程序中的用法有一些区别,一些特殊的地方需要特别注意.从笔者的经验来看,WDK给出的AVStream小端口驱动示例工程, ...

  6. Linux USB驱动程序设计

    Linux USB驱动程序设计 1. USB发展史 USB(Universal Serial Bus ),通用串行总线,是一种外部总线标准,用于规范电脑与外部设备的连接和通讯. USB是在1994年底 ...

  7. Linux USB设备驱动程序设计 和 USB下载线驱动设计

    Linux USB设备驱动程序设计 和 USB下载线驱动设计 USB设备驱动模型 USB设备包括配置(configuration).接口(interface)和端点(endpoint),一个USB设备 ...

  8. 【转】s3c2440 按键驱动 — 字符设备

    原文网址:http://www.xuebuyuan.com/632893.html 主机:VM - redhat 9.0 开发板:FL2440,linux-2.6.12 arm-linux-gcc:3 ...

  9. Linux 进程间通信 --- 信号通信 --- signal --- signal(SIGINT, my_func); --- 按键驱动异步通知(转)...

    信号  ( signal ) 机制是 UNIX 系统中最为古老的进程间通信机制,很多条件可以产生一个信号. 信号的产生: 1,当用户按下某些按键时,产生信号. 2,硬件异常产生信号:除数为 0 ,无效 ...

  10. [RK3288][Android6.0] 系统按键驱动流程分析【转】

    本文转载自:http://blog.csdn.net/kris_fei/article/details/77894406 Rockchip的按键驱动位于 kernel/drivers/input/ke ...

最新文章

  1. 华为服务器内存条在主板位置,服务器主板内存
  2. 用U盘破除XP管理员密码
  3. Spring学习笔记-注入实战篇
  4. 10行代码AC——UVa 10940(Throwing cards away II 数学规律+约瑟夫环)
  5. android compile使用方法,自己创建一个android studio在线依赖compile
  6. python的open方法_Python os.open() 方法
  7. JAVA进阶教学之(Object类中的hashCode方法)
  8. ubuntu命令查询版本和内核版本
  9. 快速排序(递归)-三路快速排序(图解)及代码
  10. jsp进阶教程和Servlet
  11. 使用docker部署java服务
  12. C# vb .net实现焦距淡色特效滤镜
  13. c语言软件如何调字间距,sublime text2如何更改行间距和字符间距?
  14. 敏捷软件开发宣言和原则
  15. Markdown排版微信公众号文章
  16. WeCenter 与 UCenter 对接
  17. samba 服务器配置
  18. 自媒体必备工具:免费的音文对齐生成SRT字幕,快速打轴匹配声音及文字的在线工具
  19. 计算机专业有那些?原来有这么这么多
  20. Windows10安装Ubuntu子系统+配置SSH连接+安装xfce4图形界面+配置xrdc远程桌面连接

热门文章

  1. 实习踩坑之路:LocalDateTime计算间隔天数,compareTo/Period的beetween方法导致的bug
  2. 异常信息_共同药业被爆:大客户异常 瞒报环保处罚信息
  3. Flink Kafka 端到端 Exactly-Once 分析
  4. 基于 Flink 构建 CEP 引擎的挑战和实践
  5. Request中Attribute 和 Parameter 的区别
  6. php 代码格式化命令,go fmt命令——格式化代码文件
  7. github可以刷星吗_国内某知名社区居然也在GitHub上玩起了刷星活动
  8. python install_[Python] Linux下python install
  9. 肌电信号 原始信号 积分_实验室人必看!复杂的色谱峰要如何正确积分?
  10. python循环语句打印矩形_pycharm软件python的一些循环语句的用法