zoukankan      html  css  js  c++  java
  • linux-2.6内核驱动学习——jz2440之按键

     
    //以下是学习完韦东山老师视屏教程后所做学习记录
    中断方式取得按键值:
      1 #include <linux/module.h>
      2 #include <linux/kernel.h>
      3 #include <linux/fs.h>
      4 #include <linux/init.h>
      5 #include <linux/delay.h>
      6 #include <linux/irq.h>
      7 #include <asm/uaccess.h>
      8 #include <asm/irq.h>
      9 #include <asm/io.h>
     10 #include <asm/arch/regs-gpio.h>
     11 #include <asm/hardware.h>
     12 
     13 
     14 static struct class *thirddrv_class;
     15 static struct class_device    *thirddrv_class_dev;
     16 
     17 volatile unsigned long *gpfcon;
     18 volatile unsigned long *gpfdat;
     19 
     20 volatile unsigned long *gpgcon;
     21 volatile unsigned long *gpgdat;
     22 
     23 
     24 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
     25 
     26 /* 中断事件标志, 中断服务程序将它置1,third_drv_read将它清0 */
     27 static volatile int ev_press = 0;
     28 
     29 
     30 struct pin_desc{
     31     unsigned int pin;
     32     unsigned int key_val;
     33 };
     34 
     35 
     36 /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
     37 /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
     38 static unsigned char key_val;
     39 
     40 struct pin_desc pins_desc[4] = {
     41     {S3C2410_GPF0, 0x01},
     42     {S3C2410_GPF2, 0x02},
     43     {S3C2410_GPG3, 0x03},
     44     {S3C2410_GPG11, 0x04},
     45 };
     46 
     47 
     48 /*
     49   * 确定按键值
     50   */
     51 static irqreturn_t buttons_irq(int irq, void *dev_id)
     52 {
     53     struct pin_desc * pindesc = (struct pin_desc *)dev_id;
     54     unsigned int pinval;
     55     
     56     pinval = s3c2410_gpio_getpin(pindesc->pin);
     57 
     58     if (pinval)
     59     {
     60         /* 松开 */
     61         key_val = 0x80 | pindesc->key_val;
     62     }
     63     else
     64     {
     65         /* 按下 */
     66         key_val = pindesc->key_val;
     67     }
     68 
     69     ev_press = 1;                  /* 表示中断发生了 */
     70     wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
     71 
     72     
     73     return IRQ_RETVAL(IRQ_HANDLED);
     74 }
     75 
     76 static int third_drv_open(struct inode *inode, struct file *file)
     77 {
     78     /* 配置GPF0,2为输入引脚 */
     79     /* 配置GPG3,11为输入引脚 */
     80     request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
     81     request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
     82     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
     83     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);    
     84 
     85     return 0;
     86 }
     87 
     88 ssize_t third_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
     89 {
     90     if (size != 1)
     91         return -EINVAL;
     92 
     93     /* 如果没有按键动作, 休眠 */
     94     wait_event_interruptible(button_waitq, ev_press);
     95 
     96     /* 如果有按键动作, 返回键值 */
     97     copy_to_user(buf, &key_val, 1);
     98     ev_press = 0;
     99     
    100     return 1;
    101 }
    102 
    103 
    104 int third_drv_close(struct inode *inode, struct file *file)
    105 {
    106     free_irq(IRQ_EINT0, &pins_desc[0]);
    107     free_irq(IRQ_EINT2, &pins_desc[1]);
    108     free_irq(IRQ_EINT11, &pins_desc[2]);
    109     free_irq(IRQ_EINT19, &pins_desc[3]);
    110     return 0;
    111 }
    112 
    113 
    114 static struct file_operations sencod_drv_fops = {
    115     .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    116     .open    =  third_drv_open,     
    117     .read     =    third_drv_read,       
    118     .release =  third_drv_close,       
    119 };
    120 
    121 
    122 int major;
    123 static int third_drv_init(void)
    124 {
    125     major = register_chrdev(0, "third_drv", &sencod_drv_fops);
    126 
    127     thirddrv_class = class_create(THIS_MODULE, "third_drv");
    128 
    129     thirddrv_class_dev = class_device_create(thirddrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */
    130 
    131     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    132     gpfdat = gpfcon + 1;
    133 
    134     gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    135     gpgdat = gpgcon + 1;
    136 
    137     return 0;
    138 }
    139 
    140 static void third_drv_exit(void)
    141 {
    142     unregister_chrdev(major, "third_drv");
    143     class_device_unregister(thirddrv_class_dev);
    144     class_destroy(thirddrv_class);
    145     iounmap(gpfcon);
    146     iounmap(gpgcon);
    147     return 0;
    148 }
    149 
    150 
    151 module_init(third_drv_init);
    152 
    153 module_exit(third_drv_exit);
    154 
    155 MODULE_LICENSE("GPL");
    driver Code

    测试用例:

     1 #include <sys/types.h>
     2 #include <sys/stat.h>
     3 #include <fcntl.h>
     4 #include <stdio.h>
     5 
     6 /* thirddrvtest 
     7   */
     8 int main(int argc, char **argv)
     9 {
    10     int fd;
    11     unsigned char key_val;
    12     
    13     fd = open("/dev/buttons", O_RDWR);
    14     if (fd < 0)
    15     {
    16         printf("can't open!
    ");
    17     }
    18 
    19     while (1)
    20     {
    21         read(fd, &key_val, 1);
    22         printf("key_val = 0x%x
    ", key_val);
    23     }
    24     
    25     return 0;
    26 }
    drvtest Code

    以上是采用中断方式的写法。

    下面学习了poll机制后,做了改进:

    drv Code

    测试用例如下:

     1 #include <sys/types.h>
     2 #include <sys/stat.h>
     3 #include <fcntl.h>
     4 #include <stdio.h>
     5 #include <poll.h>
     6 
     7 
     8 /* forthdrvtest 
     9   */
    10 int main(int argc, char **argv)
    11 {
    12     int fd;
    13     unsigned char key_val;
    14     int ret;
    15 
    16     struct pollfd fds[1];
    17     
    18     fd = open("/dev/buttons", O_RDWR);
    19     if (fd < 0)
    20     {
    21         printf("can't open!
    ");
    22     }
    23 
    24     fds[0].fd     = fd;
    25     fds[0].events = POLLIN;
    26     while (1)
    27     {
    28         ret = poll(fds, 1, 5000);
    29         if (ret == 0)
    30         {
    31             printf("time out
    ");
    32         }
    33         else
    34         {
    35             read(fd, &key_val, 1);
    36             printf("key_val = 0x%x
    ", key_val);
    37         }
    38     }
    39     
    40     return 0;
    41 }
    drvtest view

    小总结:

      查询方式:消耗资源,高达90%以上

      中断:read()

      poll:指定超时时间

    都是应用程序主动去读。

    下面通过异步通知来改进。

    先做一个简单的测试

     1 #include <stdio.h>
     2 #include <signal.h>
     3 void my_signal_fun(int signum)
     4 {
     5     static int cnt = 0;
     6     printf("signal = %d,%d times",signum,++cnt);
     7 }
     8 
     9 int main(int argc,char *argv)
    10 {
    11     signal(SIGUSR1,my_signal_fun);
    12     while(1)
    13     {
    14         sleep(1000);        
    15     }
    16     return 0;
    17 }
    signal Code

    要点:  1.注册一个信号处理函数

         2.谁发?发给谁?怎么发?

    目标:按下按键是,驱动程序通知应用程序,

        1、应用程序要注册信号处理函数。

        2、驱动程序发信号给应用程序  (应用程序要告诉驱动PID号)

        3、怎么发?

    用到signal、fcntl

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/init.h>
    #include <linux/delay.h>
    #include <linux/irq.h>
    #include <asm/uaccess.h>
    #include <asm/irq.h>
    #include <asm/io.h>
    #include <asm/arch/regs-gpio.h>
    #include <asm/hardware.h>
    #include <linux/poll.h>
    
    
    static struct class *fifthdrv_class;
    static struct class_device    *fifthdrv_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);
    
    /* 中断事件标志, 中断服务程序将它置1,fifth_drv_read将它清0 */
    static volatile int ev_press = 0;
    
    static struct fasync_struct *button_async;
    
    
    struct pin_desc{
        unsigned int pin;
        unsigned int key_val;
    };
    
    
    /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
    /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
    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);   /* 唤醒休眠的进程 */
        
        kill_fasync (&button_async, SIGIO, POLL_IN);
        
        return IRQ_RETVAL(IRQ_HANDLED);
    }
    
    static int fifth_drv_open(struct inode *inode, struct file *file)
    {
        /* 配置GPF0,2为输入引脚 */
        /* 配置GPG3,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]);    
    
        return 0;
    }
    
    ssize_t fifth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
    {
        if (size != 1)
            return -EINVAL;
    
        /* 如果没有按键动作, 休眠 */
        wait_event_interruptible(button_waitq, ev_press);
    
        /* 如果有按键动作, 返回键值 */
        copy_to_user(buf, &key_val, 1);
        ev_press = 0;
        
        return 1;
    }
    
    
    int fifth_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_EINT11, &pins_desc[2]);
        free_irq(IRQ_EINT19, &pins_desc[3]);
        return 0;
    }
    
    static unsigned fifth_drv_poll(struct file *file, poll_table *wait)
    {
        unsigned int mask = 0;
        poll_wait(file, &button_waitq, wait); // 不会立即休眠
    
        if (ev_press)
            mask |= POLLIN | POLLRDNORM;
    
        return mask;
    }
    
    static int fifth_drv_fasync (int fd, struct file *filp, int on)
    {
        printk("driver: fifth_drv_fasync
    ");
        return fasync_helper (fd, filp, on, &button_async);
    }
    
    
    static struct file_operations sencod_drv_fops = {
        .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
        .open    =  fifth_drv_open,     
        .read     =    fifth_drv_read,       
        .release =  fifth_drv_close,
        .poll    =  fifth_drv_poll,
        .fasync     =  fifth_drv_fasync,
    };
    
    
    int major;
    static int fifth_drv_init(void)
    {
        major = register_chrdev(0, "fifth_drv", &sencod_drv_fops);
    
        fifthdrv_class = class_create(THIS_MODULE, "fifth_drv");
    
        fifthdrv_class_dev = class_device_create(fifthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */
    
        gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
        gpfdat = gpfcon + 1;
    
        gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
        gpgdat = gpgcon + 1;
    
        return 0;
    }
    
    static void fifth_drv_exit(void)
    {
        unregister_chrdev(major, "fifth_drv");
        class_device_unregister(fifthdrv_class_dev);
        class_destroy(fifthdrv_class);
        iounmap(gpfcon);
        iounmap(gpgcon);
        return 0;
    }
    
    
    module_init(fifth_drv_init);
    
    module_exit(fifth_drv_exit);
    
    MODULE_LICENSE("GPL");
    driver Code

    测试用例:

     1 #include <sys/types.h>
     2 #include <sys/stat.h>
     3 #include <fcntl.h>
     4 #include <stdio.h>
     5 #include <poll.h>
     6 #include <signal.h>
     7 #include <sys/types.h>
     8 #include <unistd.h>
     9 #include <fcntl.h>
    10 
    11 
    12 /* fifthdrvtest 
    13   */
    14 int fd;
    15 
    16 void my_signal_fun(int signum)
    17 {
    18     unsigned char key_val;
    19     read(fd, &key_val, 1);
    20     printf("key_val: 0x%x
    ", key_val);
    21 }
    22 
    23 int main(int argc, char **argv)
    24 {
    25     unsigned char key_val;
    26     int ret;
    27     int Oflags;
    28 
    29     signal(SIGIO, my_signal_fun);
    30     
    31     fd = open("/dev/buttons", O_RDWR);
    32     if (fd < 0)
    33     {
    34         printf("can't open!
    ");
    35     }
    36 
    37     fcntl(fd, F_SETOWN, getpid());
    38     
    39     Oflags = fcntl(fd, F_GETFL); 
    40     
    41     fcntl(fd, F_SETFL, Oflags | FASYNC);
    42 
    43 
    44     while (1)
    45     {
    46         sleep(1000);
    47     }
    48     
    49     return 0;
    50 }
    drvtest code

    fcntl(fd, F_SETOWN, getpid());   //告诉内核,发给谁

    Oflags = fcntl(fd, F_GETFL);
    fcntl(fd, F_SETFL, Oflags | FASYNC); //改变fasync标记,最终会调用驱动的faync>faync_helper : 初始化/释放fasync_struct

    目前,我们这个按键驱动程序已经较完善。

    现在我们想让这个驱动同一时间只有一个app可以打开。

    如果用一个变量来控制的话,会存在漏洞,分析:

    linux是一个多任务的系统,修改一个值的时候有三个过程:1、读出;2、修改;3、写回

    修改代码不是一个原子操作,引入原子变量。

    笔记如下:

    1. 原子操作
    原子操作指的是在执行过程中不会被别的代码路径所中断的操作。
    常用原子操作函数举例:
    atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0
    atomic_read(atomic_t *v); //返回原子变量的值
    void atomic_inc(atomic_t *v); //原子变量增加1
    void atomic_dec(atomic_t *v); //原子变量减少1
    int atomic_dec_and_test(atomic_t *v); //自减操作后测试其是否为0,为0则返回true,否则返回false。

    2. 信号量
    信号量(semaphore)是用于保护临界区的一种常用方法,只有得到信号量的进程才能执行临界区代码。
    当获取不到信号量时,进程进入休眠等待状态。

    定义信号量
    struct semaphore sem;
    初始化信号量
    void sema_init (struct semaphore *sem, int val);
    void init_MUTEX(struct semaphore *sem);//初始化为0

    static DECLARE_MUTEX(button_lock); //定义互斥锁

    获得信号量
    void down(struct semaphore * sem);
    int down_interruptible(struct semaphore * sem);
    int down_trylock(struct semaphore * sem);
    释放信号量
    void up(struct semaphore * sem);

    3. 阻塞
    阻塞操作
    是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。
    被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。

    非阻塞操作
    进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止。

    fd = open("...", O_RDWR | O_NONBLOCK);

    加上按键防抖动就完美:

      1 #include <linux/module.h>
      2 #include <linux/kernel.h>
      3 #include <linux/fs.h>
      4 #include <linux/init.h>
      5 #include <linux/delay.h>
      6 #include <linux/irq.h>
      7 #include <asm/uaccess.h>
      8 #include <asm/irq.h>
      9 #include <asm/io.h>
     10 #include <asm/arch/regs-gpio.h>
     11 #include <asm/hardware.h>
     12 #include <linux/poll.h>
     13 
     14 
     15 static struct class *sixthdrv_class;
     16 static struct class_device    *sixthdrv_class_dev;
     17 
     18 volatile unsigned long *gpfcon;
     19 volatile unsigned long *gpfdat;
     20 
     21 volatile unsigned long *gpgcon;
     22 volatile unsigned long *gpgdat;
     23 
     24 static struct timer_list buttons_timer;
     25 
     26 
     27 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
     28 
     29 /* 中断事件标志, 中断服务程序将它置1,sixth_drv_read将它清0 */
     30 static volatile int ev_press = 0;
     31 
     32 static struct fasync_struct *button_async;
     33 
     34 
     35 struct pin_desc{
     36     unsigned int pin;
     37     unsigned int key_val;
     38 };
     39 
     40 
     41 /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
     42 /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
     43 static unsigned char key_val;
     44 
     45 struct pin_desc pins_desc[4] = {
     46     {S3C2410_GPF0, 0x01},
     47     {S3C2410_GPF2, 0x02},
     48     {S3C2410_GPG3, 0x03},
     49     {S3C2410_GPG11, 0x04},
     50 };
     51 
     52 static struct pin_desc *irq_pd;
     53 
     54 //static atomic_t canopen = ATOMIC_INIT(1);     //定义原子变量并初始化为1
     55 
     56 static DECLARE_MUTEX(button_lock);     //定义互斥锁
     57 
     58 /*
     59   * 确定按键值
     60   */
     61 static irqreturn_t buttons_irq(int irq, void *dev_id)
     62 {
     63     /* 10ms后启动定时器 */
     64     irq_pd = (struct pin_desc *)dev_id;
     65     mod_timer(&buttons_timer, jiffies+HZ/100);
     66     return IRQ_RETVAL(IRQ_HANDLED);
     67 }
     68 
     69 static int sixth_drv_open(struct inode *inode, struct file *file)
     70 {
     71 #if 0    
     72     if (!atomic_dec_and_test(&canopen))
     73     {
     74         atomic_inc(&canopen);
     75         return -EBUSY;
     76     }
     77 #endif        
     78 
     79     if (file->f_flags & O_NONBLOCK)
     80     {
     81         if (down_trylock(&button_lock))
     82             return -EBUSY;
     83     }
     84     else
     85     {
     86         /* 获取信号量 */
     87         down(&button_lock);
     88     }
     89 
     90     /* 配置GPF0,2为输入引脚 */
     91     /* 配置GPG3,11为输入引脚 */
     92     request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
     93     request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
     94     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
     95     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);    
     96 
     97     return 0;
     98 }
     99 
    100 ssize_t sixth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
    101 {
    102     if (size != 1)
    103         return -EINVAL;
    104 
    105     if (file->f_flags & O_NONBLOCK)
    106     {
    107         if (!ev_press)
    108             return -EAGAIN;
    109     }
    110     else
    111     {
    112         /* 如果没有按键动作, 休眠 */
    113         wait_event_interruptible(button_waitq, ev_press);
    114     }
    115 
    116     /* 如果有按键动作, 返回键值 */
    117     copy_to_user(buf, &key_val, 1);
    118     ev_press = 0;
    119     
    120     return 1;
    121 }
    122 
    123 
    124 int sixth_drv_close(struct inode *inode, struct file *file)
    125 {
    126     //atomic_inc(&canopen);
    127     free_irq(IRQ_EINT0, &pins_desc[0]);
    128     free_irq(IRQ_EINT2, &pins_desc[1]);
    129     free_irq(IRQ_EINT11, &pins_desc[2]);
    130     free_irq(IRQ_EINT19, &pins_desc[3]);
    131     up(&button_lock);
    132     return 0;
    133 }
    134 
    135 static unsigned sixth_drv_poll(struct file *file, poll_table *wait)
    136 {
    137     unsigned int mask = 0;
    138     poll_wait(file, &button_waitq, wait); // 不会立即休眠
    139 
    140     if (ev_press)
    141         mask |= POLLIN | POLLRDNORM;
    142 
    143     return mask;
    144 }
    145 
    146 static int sixth_drv_fasync (int fd, struct file *filp, int on)
    147 {
    148     printk("driver: sixth_drv_fasync
    ");
    149     return fasync_helper (fd, filp, on, &button_async);
    150 }
    151 
    152 
    153 static struct file_operations sencod_drv_fops = {
    154     .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    155     .open    =  sixth_drv_open,     
    156     .read     =    sixth_drv_read,       
    157     .release =  sixth_drv_close,
    158     .poll    =  sixth_drv_poll,
    159     .fasync     =  sixth_drv_fasync,
    160 };
    161 
    162 
    163 int major;
    164 
    165 static void buttons_timer_function(unsigned long data)
    166 {
    167     struct pin_desc * pindesc = irq_pd;
    168     unsigned int pinval;
    169 
    170     if (!pindesc)
    171         return;
    172     
    173     pinval = s3c2410_gpio_getpin(pindesc->pin);
    174 
    175     if (pinval)
    176     {
    177         /* 松开 */
    178         key_val = 0x80 | pindesc->key_val;
    179     }
    180     else
    181     {
    182         /* 按下 */
    183         key_val = pindesc->key_val;
    184     }
    185 
    186     ev_press = 1;                  /* 表示中断发生了 */
    187     wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
    188     
    189     kill_fasync (&button_async, SIGIO, POLL_IN);
    190 }
    191 
    192 
    193 static int sixth_drv_init(void)
    194 {
    195     init_timer(&buttons_timer);
    196     buttons_timer.function = buttons_timer_function;
    197     //buttons_timer.expires  = 0;
    198     add_timer(&buttons_timer); 
    199 
    200     major = register_chrdev(0, "sixth_drv", &sencod_drv_fops);
    201 
    202     sixthdrv_class = class_create(THIS_MODULE, "sixth_drv");
    203 
    204     /* 为了让mdev根据这些信息来创建设备节点 */
    205     sixthdrv_class_dev = class_device_create(sixthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */
    206 
    207     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    208     gpfdat = gpfcon + 1;
    209 
    210     gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    211     gpgdat = gpgcon + 1;
    212 
    213     return 0;
    214 }
    215 
    216 static void sixth_drv_exit(void)
    217 {
    218     unregister_chrdev(major, "sixth_drv");
    219     class_device_unregister(sixthdrv_class_dev);
    220     class_destroy(sixthdrv_class);
    221     iounmap(gpfcon);
    222     iounmap(gpgcon);
    223     return 0;
    224 }
    225 
    226 
    227 module_init(sixth_drv_init);
    228 
    229 module_exit(sixth_drv_exit);
    230 
    231 MODULE_LICENSE("GPL");
    driver Code

    测试程序:

     1 #include <sys/types.h>
     2 #include <sys/stat.h>
     3 #include <fcntl.h>
     4 #include <stdio.h>
     5 #include <poll.h>
     6 #include <signal.h>
     7 #include <sys/types.h>
     8 #include <unistd.h>
     9 #include <fcntl.h>
    10 
    11 
    12 /* sixthdrvtest 
    13   */
    14 int fd;
    15 
    16 void my_signal_fun(int signum)
    17 {
    18     unsigned char key_val;
    19     read(fd, &key_val, 1);
    20     printf("key_val: 0x%x
    ", key_val);
    21 }
    22 
    23 int main(int argc, char **argv)
    24 {
    25     unsigned char key_val;
    26     int ret;
    27     int Oflags;
    28 
    29     //signal(SIGIO, my_signal_fun);
    30     
    31     fd = open("/dev/buttons", O_RDWR);
    32     if (fd < 0)
    33     {
    34         printf("can't open!
    ");
    35         return -1;
    36     }
    37 
    38     //fcntl(fd, F_SETOWN, getpid());
    39     
    40     //Oflags = fcntl(fd, F_GETFL); 
    41     
    42     //fcntl(fd, F_SETFL, Oflags | FASYNC);
    43 
    44 
    45     while (1)
    46     {
    47         ret = read(fd, &key_val, 1);
    48         printf("key_val: 0x%x, ret = %d
    ", key_val, ret);
    49         //sleep(5);
    50     }
    51     
    52     return 0;
    53 }
    View Code

    驱动:

  • 相关阅读:
    在CentOS中安装VMware Tools
    引用
    iomanip头文件库函数
    第2章 寄存器(CPU工作原理)
    二维差分
    组合数学——康托展开和逆康托展开
    动态规划精讲(一)区域和检索
    动态规划精讲(一)最大子矩阵
    freopen
    动态规划精讲(一)环形子组数的最大和
  • 原文地址:https://www.cnblogs.com/jason-linux/p/10280844.html
Copyright © 2011-2022 走看看