zoukankan      html  css  js  c++  java
  • 2.字符设备驱动按键中断及休眠

    硬件相关配置:

    *S2      eint0   GPF0
    *S3      eint2   GPF2
    *S4      eint11  GPG3
    *S5      eint19  GPG11

    先看测试程序中的main函数(thirdtest.c)

     1 int main(int argc, char **argv)
     2 {
     3     int fd;
     4     unsigned char key_vals[3];
     5     
     6     /*,open返回整型变量,若值等于-1,说明打开文件出现错误,
     7      *如果为大于0的值,那么这个值代表的就是文件描述符fd*/
     8     fd = open("/dev/buttons", O_RDWR);    /*控制符:O_RDWR 读、写打开*/
     9     if(fd < 0)
    10     {
    11         printf("can not open!\n");
    12     }
    13 
    14     while(1)
    15     {
    16         read(fd, &key_val, 1);
    17         printf("key_val = 0x%x\n", key_val);
    18     }
    19     return 0;
    20 }

    (所有的操作都是以open函数来开始,它用来获取fd,然后后期的其他操作全部控制fd来完成对硬件设备的实际操作)

    应用程序打开设备,调用系统调用open时,操作系统会将文件系统对应设备文件的inode中的file_operations安装进用户进程的task_struct中的file_struct,最终会调用到调用具体文件的file_operations底层操作函数 drv_open , 在这个函数里面干什么呢?

      注册中断: 

        (1)向irq_des[irq]结构中的action链表中链入了用户注册的中断处理函数

        (2)设置中断的触发方式为边沿触发

        (3)使能中断

    1 static int drv_open(struct inode *inode, struct file *file)
    2 {
    3     /* 配置GPF0,2,GPG3,11为中断引脚 */
    4     request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", 1);
    5     request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", 1);
    6     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", 1);
    7     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", 1);    
    8     return 0;
    9 }

    现在来看 request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "S2", 1);

    1 int request_irq(unsigned int irq, irq_handler_t handler,
    2         unsigned long irqflags, const char *devname, void *dev_id)
    3     
    4 irq:中断号
    5 handler:处理函数
    6 irqflags:上升沿触发,下降沿触发,边沿触发等。指定了快速中断或中断共享等中断处理属性.
    7 *devname:中断名字。通常是设备驱动程序的名称。改值用在 /proc/interrupt 系统 (虚拟)
    8 文件上,或内核发生中断错误时使用。
    9 dev_id 可作为共享中断时的中断区别参数,也可以用来指定中断服务函数需要参考的数据地址。也用于卸载action

      1.确定中断号,可以查看这个函数的调用 s3c24xx_init_irq 很明显的看到能够使用的宏在 include/asm-arm/arch/irqs.h中定义

    1 #define IRQ_EINT0      S3C2410_IRQ(0)        /*对应宏为 16 */
    2 #define IRQ_EINT2      S3C2410_IRQ(2)
    3 #define IRQ_EINT11     S3C2410_IRQ(39)
    4 #define IRQ_EINT19     S3C2410_IRQ(47)

      2.中断标志irqflags,同样在 s3c24xx_init_irq 找到相关的 set_irq_chip,找到对应的chip,深入分析下set_type函数,最后在include/asm-arm/irq.h 发现双边沿触发的宏。

    1 ......
    2 #define __IRQT_FALEDGE    IRQ_TYPE_EDGE_FALLING 
    3 #define __IRQT_RISEDGE    IRQ_TYPE_EDGE_RISING    
    4   .....
    5 #define IRQT_BOTHEDGE    (__IRQT_RISEDGE|__IRQT_FALEDGE)    
    1 #define IRQ_TYPE_EDGE_RISING    0x00000001    /* Edge rising type */
    2 #define IRQ_TYPE_EDGE_FALLING    0x00000002    /* Edge falling type */

      3.char *devname中断名随便取名

        分别取名为“s2, s3, s3, s4”

      4.dev_id可用作释放中断函数中删除action的标识,这里可以先写作1

      5. handler中断处理函数

    1 /*功能打印中断号*/
    2 static irqreturn_t buttons_irq(int irq, void *dev_id)
    3 {
    4     printk("irq%d\r\n",irq);
    5     return IRQ_HANDLED;
    6 }

      

      关闭中断:这里需要增加释放删除action链表的函数

    1 int drv_close(struct inode *inode, struct file *file)
    2 {
    3     free_irq(IRQ_EINT0, 1);
    4     free_irq(IRQ_EINT2, 1);
    5     free_irq(IRQ_EINT11,1);
    6     free_irq(IRQ_EINT19,1);
    7     return 0;
    8 }

      回到main函数,open配置中断之后,得到正确的文件描述符fd, 进入while循环,执行read函数,最终会执行到底层操作函数drv_read

    1 static ssize_t drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
    2 {
      /*此处并不实现其他功能*/
    3 return 0; 4 }

      最后,测试按键触发中断,打印设备号。

    完整程序:

     1 #include <sys/types.h>
     2 #include <sys/stat.h>
     3 #include <fcntl.h>
     4 #include <stdio.h>
     5 
     6 /* thirddrvtest on
     7   */
     8 int main(int argc, char **argv)
     9 {
    10     int fd;
    11     unsigned char key_vals[3];
    12     
    13     /*,open返回的是一个整型变量,如果这个值等于-1,说明打开文件出现错误,
    14      *如果为大于0的值,那么这个值代表的就是文件描述符fd*/
    15     fd = open("/dev/buttons", O_RDWR);    /*O_RDWR 读、写打开*/
    16     if(fd < 0)
    17     {
    18         printf("can not open!\n");
    19     }
    20 
    21     while(1)
    22     {
    23         read(fd, &key_val, 1);
    24         printf("key_val = 0x%x\n", key_val);
    25     }
    26     return 0;
    27 }
    drv_test.c
     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/interrupt.h>
    13 
    14 
    15 
    16 volatile unsigned long *gpfcon;
    17 volatile unsigned long *gpfdat;
    18 volatile unsigned long *gpgcon;
    19 volatile unsigned long *gpgdat;
    20 
    21 
    22 static struct class *drv_class;
    23 static struct class_device    *drv_class_dev;
    24 
    25 static irqreturn_t buttons_irq(int irq, void *dev_id)
    26 {
    27     printk("irq%d\r\n",irq);
    28     return IRQ_HANDLED;
    29 }
    30 
    31 static int drv_open(struct inode *inode, struct file *file)
    32 {
    33     /* 配置GPF0,2为输入引脚 */
    34     /* 配置GPG3,11为输入引脚 */
    35     request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", 1);
    36     request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", 1);
    37     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", 1);
    38     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", 1);    
    39     return 0;
    40 }
    41 
    42 int drv_close(struct inode *inode, struct file *file)
    43 {
    44     free_irq(IRQ_EINT0, 1);
    45     free_irq(IRQ_EINT2, 1);
    46     free_irq(IRQ_EINT11,1);
    47     free_irq(IRQ_EINT19,1);
    48     return 0;
    49 }
    50 
    51 
    52 static ssize_t drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
    53 {
    54     //int minor =  MINOR(file->f_dentry->d_inode->i_rdev);
    55     //printk("drv_write=%d\n",minor);
    56     return 0;
    57 }
    58 
    59 static ssize_t drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
    60 {
    61     return 0;
    62 }
    63 
    64 
    65 static struct file_operations drv_fops = {
    66     .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    67     .open   =   drv_open,     
    68     .write    =    drv_write,
    69     .read    =    drv_read,     
    70     .release =  drv_close,  
    71 };
    72 
    73 static int major;
    74 static int drv_init(void)
    75 {
    76     int minor=0;
    77     major=register_chrdev(0, "drv", &drv_fops); // 注册, 告诉内核
    78     drv_class = class_create(THIS_MODULE, "drv");
    79     drv_class_dev = class_device_create(drv_class, NULL, MKDEV(major, 0), NULL, "xyz%d", minor);
    80 
    81     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    82     gpfdat = gpfcon + 1;
    83     gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    84     gpgdat = gpgcon + 1;
    85     return 0;
    86 }
    87 
    88 static void drv_exit(void)
    89 {
    90     unregister_chrdev(major, "drv"); // 卸载
    91     class_device_unregister(drv_class_dev);
    92     class_destroy(drv_class);
    93     iounmap(gpfcon);
    94     iounmap(gpgcon);
    95 }
    96 
    97 module_init(drv_init);
    98 module_exit(drv_exit);
    99 MODULE_LICENSE("GPL");
    drv.c

     

    改进1如何区分是不同的按键,按下还是松开,并读出按键值?

      要读出引脚的电平,在裸机学习中,可知,可以通过读取对应寄存器,进行移位操作来获取引脚状态

     1         /* 读GPF0,2 */
     2     regval = *gpfdat;
     3     key_vals[0] = (regval & (1<<0)) ? 1 : 0;
     4     key_vals[1] = (regval & (1<<2)) ? 1 : 0;
     5     
     6 
     7     /* 读GPG3,11 */
     8     regval = *gpgdat;
     9     key_vals[2] = (regval & (1<<3)) ? 1 : 0;
    10     key_vals[3] = (regval & (1<<11)) ? 1 : 0;        
    寄存器移位读取引脚状态

      幸运的是在Linux内部有系统函数中已经有一个这样功能的函数了,直接拿来用就可以了。

      输入系统定义的引脚 pin 对应的宏 S3C24XX_GPIO_BASE(pin), 即可读出引脚电平

    1 unsigned int s3c2410_gpio_getpin(unsigned int pin)
    2 {
    3     void __iomem *base = S3C24XX_GPIO_BASE(pin);
    4     unsigned long offs = S3C2410_GPIO_OFFSET(pin);
    5 
    6     return __raw_readl(base + 0x04) & (1<< offs);
    7 }
    s3c2410_gpio_getpin(unsigned int pin)

    为了区分不同的按键,我们给每个按键赋一个键值,同时构造一个结构体数组,来存放这些按键对应的键值

      1.先构造一个结构体 pin_desc

    1 struct pin_desc{
    2     unsigned int pin;  
    3     unsigned int key_val;
    4 };

      2.再构造构造一个结构体数组pin_desc[4]

    1  /*键值: 按下时,0x01, 0x02, 0x03, 0x04*/
    2  /*键值: 松开时,0x81, 0x82, 0x83, 0x84*/
    3 struct pin_desc pins_desc[4] = {
    4    /*   pin      ,key_val */
    5     {S3C2410_GPF0, 0x01},
    6     {S3C2410_GPF2, 0x02},
    7     {S3C2410_GPG3, 0x03},
    8     {S3C2410_GPG11,0x04},
    9 };

    OK, 那怎么使用这个数组呢?(将引脚的键值,通过注册函数的dev_id 注册进去)

     1 static int third_drv_open(struct inode *inode, struct file *file)
     2 {
     3     //GPF0 GPF2  GPG3 GPG11,使用虚拟地址
     4     /*设置GPF0,2  GPG3,11为中断引脚*/
     5     request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "s2",  &pins_desc[0]);
     6     request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "s3",  &pins_desc[1]);
     7     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "s4",  &pins_desc[2]);
     8     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "s5",  &pins_desc[3]);
     9     return 0; 
    10 }
    third_drv_open
    1 int third_drv_close(struct inode *inode, struct file *file)
    2 {
    3     free_irq(IRQ_EINT0,  &pins_desc[0]);
    4     free_irq(IRQ_EINT2,  &pins_desc[1]);
    5     free_irq(IRQ_EINT11, &pins_desc[2]);
    6     free_irq(IRQ_EINT19, &pins_desc[3]);
    7     return 0;
    8 }
    third_drv_close

    引脚的键值已经配置好了,那怎么读出单个引脚状态值所对应的键值呢?

     通过读取 s3c2410_gpio_getpin 

     1 /*确定按键值*/
     2 static irqreturn_t buttons_irq(int irq, void *dev_id)
     3 {
     4     /*在中断处理函数中如何使用pins_desc[4] ?*/
     5     struct pin_desc *pin = (struct pin_desc *)dev_id;
     6     unsigned int pinval;
     7     
     8     /*系统函数,可读出单个引脚状态值,高低电平*/
     9     pinval = s3c2410_gpio_getpin(pin_desc->pin);  /* 1 / 0 */
    10 
    11     /*确定按键值*/
    12     if (pinval)
    13     {
    14         /* 为1--松开 */
    15         key_val = 0x80 | pin_desc->key_val;
    16         
    17     }
    18     else
    19     {
    20         /* 0--按下 */
    21         key_val = pin_desc->key_val;
    25     
    26     return IRQ_HANDLED;
    27 }

      注册号中断引脚之后,发生中断,引脚及键值的地址--&pins_desc[0],就被传入中断处理函数

      如何使用pins_desc[i] 来将引脚传递给 s3c2410_gpio_getpin(unsigned int pin)

      构造结构体指针,利用由request初始化的 dev_id 指针传递参数,第5-9行,通过指向pin_desc的指针,把pin传递给它。

    改进2:

      我们使用中断的目的,就是为了在中断发生时,才去读操作,避免像查询一样一直read,从而占据大量的CPU。

      休眠读取:

    程序设计目的:App去读取按键值,如果有按键中断触发(键值有改变)则打印,否则休眠.

    如上框图所示:

      在main函数中,进入while(1)死循环之后,执行read操作,

      若按键值更新,则读取键值

      若未更新,则进入休眠并等待更新,更新后,唤醒进程。

    如何设置休眠机制?

      驱动程序中需要设计休眠,中断发生来唤醒首先定义一个等待队列,下述是一个宏

    1 //生成一个等待队列头wait_queue_head_t,名字为name
    2 DECLARE_WAIT_QUEUE_HEAD(name) 
    3 
    4 // 定义一个名为`button_waitq`的队列
    5 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

      休眠函数如下,condition=0才休眠,定义在include/linux/wait.h

    1 #define wait_event_interruptible(wq, condition)                \
    2 ({                                    \
    3     int __ret = 0;                            \
    4     if (!(condition))                        \
    5         __wait_event_interruptible(wq, condition, __ret);    \
    6     __ret;                                \
    7 })

      唤醒也是一个宏,参数是等待队列,放置在中断函数处理中,定义在include/linux/wait.h

    1 wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */

      在read函数中设置

     1 ssize_t third_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
     2 {    
     3   /*size 在此即为sizeof(key_val), 例如:0x01,一个字节大小*/
     4     if(size != 1)
     5     return -EINVAL;
     6 
     7     /*如果没有按键动作,ev_press = 0, 将进程挂在队列里面等待,休眠, 不会执行下面的函数*/
     8     wait_event_interruptible(button_waitq, ev_press);
     9     //谁来唤醒进程?-> 中断发生的时候,就唤醒进程
    10     
    11     /*/*如果有按键动作,ev_press = 1,会执行到此函数,并返回键值,将变量清零*/*/
    12     copy_to_user(buf, &key_val, 1);
    13     ev_press = 0;  /*清零,为下一次操作赋初值*/
    14     return 1;
    15 }

      在third_drv_open中设置

     1 /*确定按键值*/
     2 static irqreturn_t buttons_irq(int irq, void *dev_id)
     3 {
     4     /*在中断处理函数中如何使用pins_desc[4] */
     5     struct pin_desc *pin = (struct pin_desc *)dev_id;
     6     unsigned int pinval;
     7     
     8     /*系统函数,可读出单个引脚状态值,高低电平*/
     9     pinval = s3c2410_gpio_getpin(pin_desc->pin);
    10 
    11     /*确定按键值*/
    12     if (pinval)
    13     {
    14         /* 为1--松开 */
    15         key_val = 0x80 | pin_desc->key_val;
    16         
    17     }
    18     else
    19     {
    20         /* 0--按下 */
    21         key_val = pin_desc->key_val;
    22     }
    23     ev_press = 1;    /*表示中断发生了*/
    24     wake_up_interruptible(&button_waitq);    /*去队列button_waitq里面唤醒休眠的进程*/
    25     
    26     return IRQ_HANDLED;
    27 }

     改进后的完整代码如下:

     1 // app.c
     2 #include <sys/types.h>
     3 #include <sys/stat.h>
     4 #include <fcntl.h>
     5 #include <stdio.h>
     6 #include <unistd.h>
     7 
     8 int main(int argc, char **argv)
     9 {
    10     int fd;
    11     unsigned char key_val;
    12     fd = open("/dev/xyz0", O_RDWR);
    13     if (fd < 0)
    14     {
    15         printf("can't open!\n");
    16     }
    17     while (1)
    18     {
    19         read(fd, &key_val, 1);
    20         printf("key_val = 0x%x\n", key_val);
    21     }
    22     return 0;
    23 }
    forth_drvtest.c
      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/interrupt.h>
     13 
     14 volatile unsigned long *gpfcon;
     15 volatile unsigned long *gpfdat;
     16 volatile unsigned long *gpgcon;
     17 volatile unsigned long *gpgdat;
     18 
     19 static struct class *drv_class;
     20 static struct class_device    *drv_class_dev;
     21 
     22 // 定义一个名为`button_waitq`的队列
     23 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
     24 // flag=1 means irq happened and need to update
     25 int flag=0;
     26 
     27 struct pin_desc{
     28     unsigned int pin;
     29     unsigned int key_val;
     30 };
     31 
     32 /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
     33 /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
     34 static unsigned char key_val;
     35 
     36 struct pin_desc pins_desc[4] = {
     37     {S3C2410_GPF0, 0x01},
     38     {S3C2410_GPF2, 0x02},
     39     {S3C2410_GPG3, 0x03},
     40     {S3C2410_GPG11, 0x04},
     41 };
     42 
     43 static irqreturn_t buttons_irq(int irq, void *dev_id)
     44 {
     45     printk("irq%d\r\n",irq);
     46 
     47     struct pin_desc * pindesc = (struct pin_desc *)dev_id;
     48     unsigned int pinval;
     49     
     50     pinval = s3c2410_gpio_getpin(pindesc->pin);
     51 
     52     if (pinval)
     53     {
     54         /* 松开 */
     55         key_val = 0x80 | pindesc->key_val;
     56     }
     57     else
     58     {
     59         /* 按下 */
     60         key_val = pindesc->key_val;
     61     }
     62 
     63     wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
     64     flag=1;
     65 
     66     return IRQ_RETVAL(IRQ_HANDLED);
     67 }
     68 
     69 static int drv_open(struct inode *inode, struct file *file)
     70 {
     71     /* 配置GPF0,2为输入引脚 */
     72     /* 配置GPG3,11为输入引脚 */
     73     request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
     74     request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
     75     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
     76     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);    
     77     return 0;
     78 }
     79 
     80 int drv_close(struct inode *inode, struct file *file)
     81 {
     82     free_irq(IRQ_EINT0, &pins_desc[0]);
     83     free_irq(IRQ_EINT2, &pins_desc[1]);
     84     free_irq(IRQ_EINT11,&pins_desc[2]);
     85     free_irq(IRQ_EINT19,&pins_desc[3]);
     86     return 0;
     87 }
     88 
     89 
     90 static ssize_t drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
     91 {
     92     //int minor =  MINOR(file->f_dentry->d_inode->i_rdev);
     93     //printk("drv_write=%d\n",minor);
     94     return 0;
     95 }
     96 
     97 static ssize_t drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
     98 {
     99     if (size != 1)
    100     return -EINVAL;
    101 
    102     /* 如果没有按键动作, 休眠 */
    103     wait_event_interruptible(button_waitq, flag);
    104 
    105     /* 如果有按键动作, 返回键值 */
    106     copy_to_user(buf, &key_val, 1);
    107     flag = 0;
    108     
    109     return 1;
    110 }
    111 
    112 
    113 static struct file_operations drv_fops = {
    114     .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    115     .open   =   drv_open,     
    116     .write    =    drv_write,
    117     .read    =    drv_read,     
    118     .release =  drv_close,  
    119 };
    120 
    121 static int major;
    122 static int drv_init(void)
    123 {
    124     int minor=0;
    125     major=register_chrdev(0, "drv", &drv_fops); // 注册, 告诉内核
    126     drv_class = class_create(THIS_MODULE, "drv");
    127     drv_class_dev = class_device_create(drv_class, NULL, MKDEV(major, 0), NULL, "xyz%d", minor);
    128 
    129     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
    130     gpfdat = gpfcon + 1;
    131     gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
    132     gpgdat = gpgcon + 1;
    133     return 0;
    134 }
    135 
    136 static void drv_exit(void)
    137 {
    138     unregister_chrdev(major, "drv"); // 卸载
    139     class_device_unregister(drv_class_dev);
    140     class_destroy(drv_class);
    141     iounmap(gpfcon);
    142     iounmap(gpgcon);
    143 }
    144 
    145 module_init(drv_init);
    146 module_exit(drv_exit);
    147 MODULE_AUTHOR("xxx");
    148 MODULE_VERSION("0.1.0");
    149 MODULE_DESCRIPTION("S3C2410/S3C2440 LED Driver");
    150 MODULE_LICENSE("GPL");
    forth_drv.c

    测试

    测试运行./text /dev/xyz0 & 后台运行

    # ./test /dev/xyz0 &
    # irq55
    key_val = 0x3
    irq55
    key_val = 0x83
    irq18
    key_val = 0x2
    irq18
    key_val = 0x82
    irq16
    key_val = 0x1
    irq16
    key_val = 0x81
    irq63
    key_val = 0x4
    irq63
    key_val = 0x84

    使用top查看占用

      Load average: 0.00 0.01 0.00
      PID  PPID USER     STAT   VSZ %MEM %CPU COMMAND
      782   770 0        R     3096   5%   0% top
      770     1 0        S     3096   5%   0% -sh
      781   770 0        S     1312   2%   0% ./test /dev/xyz0

    使用ps查看任务为S状态 休眠状态

    # ps
      PID  Uid        VSZ Stat Command
        1 0          3092 S   init
      781 0          1312 S   ./test /dev/xyz0
      783 0          3096 R   ps
  • 相关阅读:
    PYTHON 中的字符集
    字符集--发展史
    循序渐进Python3(十三) --7--  django之models
    循序渐进Python3(十三) --8--  django之admin
    循序渐进Python3(十三) --6--  cookie和session
    循序渐进Python3(十三) --5-- django请求处理流程
    循序渐进Python3(十三) --4-- django之csrf使用
    循序渐进Python3(十三) --3-- django之form表单(为自动生成的html标签添加样式)
    循序渐进Python3(十三) --2-- django之form表单(自动生成html标签和自定制提示信息)
    循序渐进Python3(十三) --1-- django之form表单
  • 原文地址:https://www.cnblogs.com/y4247464/p/10105099.html
Copyright © 2011-2022 走看看