linux4.1中断程序,4.1 big-bird linux之字符设备驱动程序之中断方式的按键驱动

一、按下按键(中断框架requst_irq)

1、CPU进入异常模式b vector_irq + offset

2、调用irq_user

3、b

asm_do_IRQ

4、irq_desc[irq]

-> handle_irq

5、handle_edge_irq :

① desc -> chip

-> ack(irq) :清中断

hadle_IRQ_event :处理中断

取出action链表中的成员,执行action -> handler

(1)发生中断时,CPU执行异常向量 vector_irq 的代码。

(2)在 vector_irq 里面,最终会调用中断处理的总入口函数asm_do_IRQ。

(3)asm_do_IRQ 根据中断号调用 irq_desc 数组项中的handle_irq。

(4)handle_irq 会使用chip成员中的函数来设置硬件。

(5)handle_irq 逐个调用用户在 action 链表中注册的处理函数。

二、注册中断处理程序

int

request_irq(unsigned int

irq, //中断号

irq_handler_t

handler, //处理函数

unsigned long

irqflags, //触发方式

const char

*devname, //函数名

void

*dev_id) //设备号

(Manage.c

(kernel\irq))

{

① 分配irqaction结构,该结构中的成员指向传入的参数

② setup_irq(irq, action);

a、找到 irq_desc[irq]

在 irq_desc[irq] ->

action 链表里加入传入参数

b、desc->chip->set_type //将对应的引脚设置为中断引脚

c、desc->chip->startup(irq);/desc->chip->enable(irq); //使能中断

}

三、卸载中断处理程序

free_irq(irq , *dev_id)

出链,禁止中断

四、驱动程序:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

static

struct class *thirddrv_class;

static

struct

class_device *thirddrv_class_dev;

volatile

unsigned long *gpfcon;

volatile

unsigned long *gpfdat;

volatile

unsigned long *gpgcon;

volatile

unsigned long *gpgdat;

static

DECLARE_WAIT_QUEUE_HEAD(button_waitq);

//定义并初始化等待队列头部,DECLARE_WAIT_QUEUE_HEAD(name);

static volatile int ev_press = 0;

struct

pin_desc{

unsigned int pin;

unsigned int key_val;

};

static

unsigned char key_val;

struct

pin_desc pins_desc[4] = {

{S3C2410_GPF0, 0x01},

{S3C2410_GPF2, 0x02},

{S3C2410_GPG3, 0x03},

{S3C2410_GPG11, 0x04},

};

static

irqreturn_t buttons_irq(int irq, void

*dev_id) //中断处理函数

{

struct pin_desc * pindesc = (struct pin_desc *)dev_id;

unsigned int pinval;

pinval = s3c2410_gpio_getpin(pindesc->pin);

//系统函数,能够读出引脚值

if (pinval)

{

key_val = 0x80 | pindesc->key_val;

}

else

{

key_val = pindesc->key_val;

}

ev_press =

1;

wake_up_interruptible(&button_waitq);

//唤醒队列,void

wake_up_interruptible(wait_queue_head_t

*queue);唤醒以queue作为等待列头部的队列中所有的进程。与wait_event_interruptuble()和wait_event_interruptuble_timeout()成对使用。

return

IRQ_RETVAL(IRQ_HANDLED); // 接收到了准确的中断信号,并且作了相应正确的处理

//中断处理例程应当返回一个值指示是否真正处理了一个中断。如果处理例程发现设备确实需要处理,应当返回IRQ_HANDLED;否则返回值IRQ_NONE。

}

static int

third_drv_open(struct inode *inode, struct file *file)

{

//

有中断请求时,会自动将能设置为中断模式的引脚设为中断模式,所以这里不用配置引脚模式,都自动配置成了中断模式11

request_irq(IRQ_EINT0, buttons_irq,

IRQT_BOTHEDGE, "S2", &pins_desc[0]);

request_irq(IRQ_EINT2, buttons_irq,

IRQT_BOTHEDGE, "S3", &pins_desc[1]);

request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4",

&pins_desc[2]);

request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5",

&pins_desc[3]);

//buttons_irq是中断处理函数,所以我们需要在驱动里边去实现这个函数

//request_irq(unsigned int irq, irq_handler_t handler, unsigned

long flags, const char *name,void *dev);

// irq是要申请的硬件中断号;handler是向系统登记的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev参数将被传递给它;flags是中断处理的属性,可以指定中断的触发方式以及处理方式,IRQT_BOTHEDGE表示双边沿触发。

return 0;

}

ssize_t

third_drv_read(struct file *file, char __user *buf, size_t size,

loff_t *f_pos)

filp是文件结构体指针;buf是用户空间内存的地址,该地址在内核空间不宜直接读写;count是要读的字节数;f_pos是读的位置相对于文件开头的偏移

{

if (size != 1)

return -EINVAL;

wait_event_interruptible(button_waitq,

ev_press);

//阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作。wait_event_interruptible(queue,condition);queue作为等待队列头部的队列被唤醒,condition必须满足,否则继续阻塞。

copy_to_user(buf, &key_val,

1);

//从内核去中读取数据到用户区

//unsigned long copy_to_user(void _user *to,

const void *from,  unsigned long

n);如果数据拷贝成功,则返回零;否则,返回没有拷贝成功的数据字节数。*to是用户空间的指针,*from是内核空间指针,n表示从内核空间向用户空间拷贝数据的字节数

ev_press =

0; //清零

return 1;

}

int

third_drv_close(struct inode *inode, struct file *file)

{

free_irq(IRQ_EINT0,

&pins_desc[0]); //释放中断,参数分别为中断号和引脚描述

free_irq(IRQ_EINT2,

&pins_desc[1]); //free_irq(IRQ_EINT0, &pins_desc[0]);表示释放对应的中断

free_irq(IRQ_EINT11, &pins_desc[2]);

free_irq(IRQ_EINT19, &pins_desc[3]);

return 0;

}

static

struct file_operations sencod_drv_fops = {

.owner = THIS_MODULE,

.open = third_drv_open,

.read = third_drv_read,

.release = third_drv_close,

};

int

major;

static int

third_drv_init(void)

{

major = register_chrdev(0, "third_drv",

&sencod_drv_fops);

//

register_chrdev(MEM_MAJOR,"mem",&memory_fops),向内核注册了一个字符设备。第一个参数是主设备号,0代表动态分配。第二个参数是设备的名字,第三个参数是文件操作指针。

thirddrv_class = class_create(THIS_MODULE, "third_drv");

thirddrv_class_dev = class_device_create(thirddrv_class, NULL,

MKDEV(major, 0), NULL, "buttons");

//在驱动初始化的代码,调用内核的class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用class_device_create

(…)函数来在/dev目录下创建相应的设备节点。

gpfcon = (volatile unsigned long *)ioremap(0x56000050,

16); //地址映射

gpfdat = gpfcon + 1;

gpgcon = (volatile unsigned long *)ioremap(0x56000060,

16);

gpgdat = gpgcon + 1;

return 0;

}

static

void third_drv_exit(void)

{

unregister_chrdev(major, "third_drv");

class_device_unregister(thirddrv_class_dev);

class_destroy(thirddrv_class);

iounmap(gpfcon);

iounmap(gpgcon);

return 0;

}

module_init(third_drv_init);

module_exit(third_drv_exit);

MODULE_LICENSE("GPL");

五、用户程序:

#include

#include

#include

#include

#include

int

main(int argc, char **argv)

{

int fd;

unsigned char key_val;

fd = open("/dev/buttons", O_RDWR);

if (fd < 0)

{

printf("can't open!\n");

}

while (1)

{

//read(fd, &key_val, 1);

//printf("key_val = 0x%x\n", key_val);

sleep(5);

}

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值