Chinaunix首页 | 论坛 | 博客
  • 博客访问: 493865
  • 博文数量: 223
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2145
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-01 10:23
个人简介

该坚持的时候坚持,该妥协的时候妥协,该放弃的时候放弃

文章分类

全部博文(223)

文章存档

2017年(56)

2016年(118)

2015年(3)

2014年(46)

我的朋友

分类: 嵌入式

2016-11-07 22:14:56

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

2.设备描述
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;
};

3.设备注册
Linux中使用misc_register函数来注册一个混杂设备驱动。
int misc_register(struct miscdevice * misc);

二、 Linux中断处理程序
1.裸机中断处理流程回顾
①初始化寄存器设置,中断有一个统一的入口
②事先设置中断处理程序
③根据中断源编号,调用中断处理程序

2.Linux中断处理流程分析
中断入口:__irq_svc(entry-arm.S)
①拿到产生中断源的编号(中断号)
②根据中断号,找到相应的irq_desc结构
③取出事先注册好的处理函数运行


3.Linux中断处理程序设计
3.1 中断注册
request_irq函数用于注册中断。
int requset_irq(unsigned int irq, void (*handler)(int , void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id);
返回:0表示成功,失败返回错误码
unsigned int irq:中断号
void (*handler)(int , void *):中断处理函数。
unsigned long flags:与中断管理有关的各种选项。
const char *devname:设备名。
void *dev_id:共享中断时使用。

在flags参数中,可以选择一些与中断管理有关的选项,如:
   
IRQF_DISABLED(SA_INTERRUPT)
如果设置该位,表示是一个“快速”中断处理程序;如果没有设置这位,那么是一个“慢速”中断处理程序。
    IRQF_SHARED(SA_SHIRQ)
该位表明该中断号是多个设备共享的。

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

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



3.3 注销中断
当设备不再需要使用中断时(通常在驱动卸载时), 应当把它们注销, 使用函数:
void free_irq(unsigned int irq, void *dev_id);

四、按键驱动硬件操作实现
key.c
  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/miscdevice.h>
  4. #include <linux/fs.h>
  5. #include <asm/uaccess.h>
  6. #include <linux/io.h>
  7. #include <linux/irqreturn.h>
  8. #include <linux/interrupt.h>

  9. #define GPFCON (volatile unsigned long*) 0x56000050
  10. #define GPFDAT (volatile unsigned long*) 0x56000054


  11. irqreturn_t key_int(int irq, void *dev_id)
  12. {
  13.     //1.检测是否发生了按键中断
  14.     
  15.     //2.清除已经发生的按键中断
  16.    
  17.     //3.打印按键值
  18.     printk("key down!\n");

  19.     return 0;
  20. }

  21. void key_hw_init()
  22. {
  23.     unsigned int *gpio_config;
  24.     unsigned short data;
  25.     
  26.     gpio_config = ioremap(GPFCON,4);
  27.     data = readw(gpio_config);
  28.     data &= ~0b11;
  29.     data |= 0b10;
  30.     writew(data, gpio_config);
  31. }

  32. int key_open(struct inode *inode, struct file *filp)
  33. {
  34.     return 0;
  35. }

  36. struct file_operations key_fops = {
  37.     .open = key_open,
  38. };

  39. struct miscdevice key_miscdev = {
  40.     .minor = 200,
  41.     .name = "tq2400key",
  42.     .fops = &key_fops,
  43. };

  44. static int button_init()
  45. {
  46.     int ret;
  47.     ret = misc_register(&key_miscdev);
  48.     if(ret != 0)
  49.     {
  50.         printk(KERN_ERR"misc_register failed\n");
  51.     }
  52.     //按键初始化
  53.     key_hw_init();
  54.     //注册中断处理程序
  55.     ret = request_irq(IRQ_EINT0, &key_int, IRQF_TRIGGER_FALLING, "tq2440key", 0);
  56.     if(ret != 0)
  57.     {
  58.         printk(KERN_ERR"request_irq failed,ret is %d\n",ret);
  59.     }
  60.     return 0;
  61. }

  62. static void button_exit()
  63. {
  64.     misc_deregister(&key_miscdev);
  65.     //注销中断处理函数
  66.     free_irq(IRQ_EINT0, 0);
  67. }

  68. module_init(button_init);
  69. module_exit(button_exit);
4.2错误总结
一开始装在内核按键后一直没反应。连内核加载成功都没有提示,甚至应该提示没有GPL协议之类的都没有。才觉得可能出错了。
助手杨给的建议:
中断号对么  
中断注册成功了么  
中断程序进去了么   
还能够再次进入中断么

于是加了ret看看有没有出错:果然提示request_irq failed,ret is -16
一查中断号冲突了

这个表明内核已经编译好了,去内核中用make menuconfig ARCH=arm去掉(用/button查到的)
Symbol: TQ2440_IRQ_BUTTON [=n]                                                   │  
  │ Prompt: EmbedSky TQ2440 Board user buttons                                       │  
  │   Defined at drivers/input/keyboard/Kconfig:336                                  │  
  │   Depends on: !S390 && INPUT && INPUT_KEYBOARD && ARCH_S3C2440                   │  
  │   Location:                                                                      │  
  │     -> Device Drivers                                                            │  
  │       -> Input device support                                                    │  
  │         -> Generic input layer (needed for keyboard, mouse, ...) (INPUT [=y])    │  
  │           -> Keyboards (INPUT_KEYBOARD [=y])  

然后就成功了


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