加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

嵌入式 Linux 驱动 —— 按键中断  (转载)

(2011-11-09 18:51:31)
标签:

杂谈

http://huao429006.blog.163.com/blog/static/171819785201082883523701/

基于2.6.30.4 的内核

   函数: int  request_irq(unsigned int irq, void (*handler) (int irq,void dev_id), unsigned long flags, const char *devname, void *dev_id)  在<linux/sched.h> 中定义。调用成功时,返回0,失败时为负数。

   irq:  中断信号线,头文件:<mach/irqs.h>

   handler:  中断处理函数 (就是中断处理函数名,如:buttons_interrupt)           

   在<linux/interrupt.h>中定义为: typedef irqreturn_t (*irq_handler_t)(int, void *);

   flags:  中断有关的位掩码,介绍如下:

   devname:  设备名(如: "simpledkey")

   dev_id:   dev_id作用主要有两点:一.在中断处理程序释放时使用到dev_id,void free_irq(unsigned int irq, void *dev_id)。

                                                        二.将使用该中断处理程序的设备结构体传递给该中断处理程序

   注意:键盘驱动程序中每个注册的中断信号线一定要使用唯一的 dev_id 否则就会出现在free_irq() 时出现Trying to free already-free IRQ 
的情况。

 

1. 中断类型: 在中使用flags:

   下面这些宏定义在:<linux/interrupt.h> 中:
    #define SA_SHIRQ            共享中断(旧版本的,2.6.19之前的内核)
    #define IRQF_SHARED         共享中断(新版本的)
    #define SA_INTERRUPT        快速中断(旧版本的)
    #define IRQF_DISABLED       快速中断(新版本的)
    #define IRQF_SAMPLE_RANDOM  表示本中断源可以用作随机数生成器的熵池
 
    2. 中断的触发类型: 在set_irq_type(irq, type)中使用
    #define IRQ_TYPE_NONE           0x00000000     未指明类型
    #define IRQ_TYPE_EDGE_RISING    0x00000001     上升沿触发
    #define IRQ_TYPE_EDGE_FALLING   0x00000002     下降沿触发
    #define IRQ_TYPE_EDGE_BOTH      (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
    #define IRQ_TYPE_LEVEL_HIGH     0x00000004     高电平触发
    #define IRQ_TYPE_LEVEL_LOW      0x00000008     低电平触发
    #define IRQ_TYPE_SENSE_MASK     0x0000000f    
    #define IRQ_TYPE_PROBE          0x00000010    

 

    通常:    int  __init   xxx_init(void)          int  __exit   xxx_exit(void);     "void"  不能少,否则会有警告。

    注意:disable_irq(int irq); 不能在中断服务程序中用使用:   disable_irq不但会禁止给定的中断,而且也会等待当前正在执行的中断处理例程完成。

下面的函数的头文件为:<asm/uaccess.h>

   unsigned long copy_to_user(void __user  *to, const  void  *from, unsigned long count);

   unsigned long copy_from_user(void  *to, const  __user  *from, unsigned long count);

经验: 

对等待对列的初始化一定要放在 kmalloc() 分配内存之后,否则会出现段错误

Kdev = kmalloc(sizeof(struct kscan_dev), GFP_KERNEL);
 if(!Kdev){
  result = -ENOMEM;
  goto fail;
 }

init_waitqueue_head(&Kdev->wq);

 

这是完全由本人自己编的键盘驱动程序:

#include<linux/fs.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/types.h>
#include<linux/cdev.h>
#include<linux/interrupt.h>
#include<asm/uaccess.h>
#include<mach/hardware.h>
#include<mach/irqs.h>
#include<mach/regs-irq.h>
#include<asm/io.h>
#include<linux/sched.h>
#include<linux/wait.h>
#include<asm/signal.h>
#include<mach/regs-gpio.h>
#define KMajor 111
int flag =0;
static int inc=0;
MODULE_AUTHOR("Huao");
MODULE_LICENSE("Dual BSD/GPL");
struct kscan_dev
{
 struct semaphore sem;
 struct cdev cdev;
 int key;
};
struct kscan_dev *Kdev;

static DECLARE_WAIT_QUEUE_HEAD(wq);
static int irqArray[4] = {
 IRQ_EINT0,IRQ_EINT1,IRQ_EINT2,IRQ_EINT4
};

static int devid[4] = {
 0,1,2,4
};

static irqreturn_t Key_Interrupt(int irq, void *dev_id)
{
 Kdev->key = 2;
 flag = 1;
 wake_up_interruptible(&wq);
 printk("get key %d!\n",Kdev->key);
 return IRQ_HANDLED;
}

static int kscan_open(struct inode *inode ,struct file *filp)

 if(inc > 0) return -ERESTARTSYS;
 inc ++;
 printk("enter kscan_open()\n");
 
 //璁块棶kscan_dev缁撴瀯 
 Kdev = container_of(inode->i_cdev, struct kscan_dev, cdev);
 filp->private_data = Kdev;
 return 0;
}

static int kscan_close(struct inode *inode ,struct file *filp)
{
 inc --;
 return 0;
}

ssize_t kscan_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
{
//buf 涓虹敤鎴风紦鍐插尯锛宖_pos涓烘枃浠跺綋鍓嶅緱鍋忕Щ閲?
 int sum;
 struct kscan_dev *dev = filp->private_data;
 if (filp->f_flags & O_NONBLOCK)
 {
  return -EAGAIN;
 }else{
  printk("read is blocked!\n");
  wait_event_interruptible(wq, flag != 0);
  flag = 0;
  sum =1;
  printk("read is woken up!\n");
 dev->key = 8;
 if(copy_to_user(buf, &dev->key, 1))
 {
  sum = -EFAULT;
 }
 }
 return sum;
}

struct file_operations kscan_fops = {
 .owner = THIS_MODULE,
 .read = kscan_read,
 .open = kscan_open,
 .release = kscan_close,
};

static void __exit Kscan_exit(void)
{
 dev_t dev_value;
 int u;
 dev_value = MKDEV(KMajor,0);
 //閲婃斁涓柇淇″彿绾?
 for(u = 0;u < 4;u ++){
  disable_irq(irqArray[u]);
  free_irq(irqArray[u], (void *)&devid[u]); 
 }
 if(Kdev)
 {
  cdev_del(&Kdev->cdev);       //鍒犻櫎璁惧
  kfree(Kdev);        //閲婃斁鍐呭瓨
 }
 unregister_chrdev_region(dev_value, 1);     //dev_value琛ㄧず璧峰鍊?
 printk(KERN_DEBUG "free irq success\n");
 printk("delete device success!\n");
}

static int __init Kscan_init(void)

 int result,err;
 dev_t dev = 0;
 int i;
 //涓柇瀵勫瓨鍣ㄧ殑鍒濆鍖?
 writel((2<<0)|(2<<2)|(2<<4)|(2<<8),S3C2410_GPFCON); //璁剧疆绔彛涓轰腑鏂?
 writel((2<<0)|(2<<4)|(2<<8)|(2<<16),S3C2410_EXTINT0); //涓嬮檷娌夸腑鏂?
 writel(readl(S3C2410_EINTPEND)|1,S3C2410_EINTPEND); //缃?琛ㄧず宸茶姹?
 writel(readl(S3C2410_EINTMASK)&0,S3C2410_EINTMASK); //娓呬腑鏂睆钄戒綅

 //KMajor 涓轰富璁惧鍙凤紝MKdev()灏嗗叾杞崲鎴恉ev_t绫诲瀷
 dev = MKDEV(KMajor,0);
 printk(KERN_NOTICE "KScan:major is %d\n",dev);
 //鍔ㄦ?佸垎閰嶈澶囧彿dev锛?琛ㄧず绗竴涓璁惧鍙凤紝1涓鸿姹傜殑涓暟锛岃澶囧悕涓篕scan
 result = register_chrdev_region(dev, 1, "kscan"); //dev 鐢ㄤ簬杈撳嚭涓昏澶囧彿
 
 if(result<0)
 {
  printk(KERN_WARNING "KScan:can`t get major\n");
  return result;
 }
 //涓簊truct kscan_dev 鍒嗛厤鍐呭瓨绌洪棿锛孏FP_KERNEL 琛ㄧず鍐呭瓨绌洪棿杩涚▼
 Kdev = kmalloc(sizeof(struct kscan_dev), GFP_KERNEL);
 if(!Kdev){
  result = -ENOMEM;
  goto fail;
 }
 //娓呯┖kscan_dev缁撴瀯浣撳唴瀛?
 memset(Kdev, 0, sizeof(struct kscan_dev));
 //鍒濆鍖栧凡鍒嗛厤鍒板緱缁撴瀯
 cdev_init(&Kdev->cdev, &kscan_fops);
 Kdev->cdev.owner = THIS_MODULE;
 Kdev->cdev.ops = &kscan_fops;
 //鍦ㄥ唴鏍镐腑娉ㄥ唽璁惧缁撴瀯淇℃伅,濡傛灉澶辫触鍒欒繑鍥炶礋寰楅敊璇爜
 err = cdev_add(&Kdev->cdev, dev, 1);
 if(err<0){
  printk(KERN_NOTICE "adding scull err is %d\n",err);
  goto fail;
 }

 //鐢宠涓柇淇″彿绾?
 for(i = 0;i < 4;i++){
  if(request_irq(irqArray[i], Key_Interrupt, 0, "kscan", (void *)&devid[i]))
  {
   //鐢宠鎴愬姛鏃惰繑鍥?锛屽け璐ヨ繑鍥炶礋鏁?
   printk("request button irq failed\n");
   return -1;
  }
 }
 //wait_queue_head_t wq;
 printk(KERN_NOTICE"***  ***init kscan successfully\n");
 return 0;
    fail:
 Kscan_exit();
 return result;
}

module_init(Kscan_init);
module_exit(Kscan_exit);

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有