WDS1期第12课 字符设备驱动 4 查询方法读按键 keys_query xxx &后台运行 top资源占用情况

一、原理图 datasheet

1. 原理图

在这里插入图片描述 在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

2. datasheet

GPF0(EINT0) GPF2(EINT2) GPG3(EINT11) GPG11(EINT19)
在这里插入图片描述
在这里插入图片描述

二、框架,内核模块代码 / 用户代码

都是字符设备,所以框架都差不多。

1. 内核驱动代码

keys_query.c

#include <linux/init.h>     // module_init module_exit
#include <linux/module.h>   // MODULE_LICENSE
#include <linux/fs.h>       // file_operations
#include <linux/cdev.h>     // cdev
#include <linux/kernel.h>
#include <linux/device.h>   // class_device
#include <asm/uaccess.h>    // copy_from_user copy_to_user
#include <asm/io.h>         // ioremap  iounmap

#define DEVICE_NAME      "keys"
int major;

volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpfdat = NULL;
volatile unsigned long *gpgcon = NULL;
volatile unsigned long *gpgdat = NULL;
#define GPFCON      (*gpfcon)
#define GPFDAT      (*gpfdat)
#define GPGCON      (*gpgcon)
#define GPGDAT      (*gpgdat)

// 用于自动创建设备节点的结构class 和 class_device
static struct class *keys_class;
static struct class_device *keys_class_dev;

// GPF0/2 GPG3/11 配置成输入模式
static int keys_open (struct inode *inode, struct file *filep)
{
    GPFCON &= ~((0x3<<0*2) | (0x3<<2*2));  // 清零
    GPGCON &= ~((0x3<<3*2) | (0x3<<11*2)); // 清零 

    return 0;
}
ssize_t keys_read (struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
    unsigned char key_vals[4];
    int regval;

    // 判断缓冲区大小
    if (size != sizeof(key_vals))
        return -EINVAL;

    // 获取GPFDAT寄存器的值
    regval = GPFDAT;
    key_vals[1] = (regval & (0x1 << 0)) ? 1 : 0; 
    key_vals[2] = (regval & (0x1 << 2)) ? 1 : 0; 
    // 获取GPGDAT寄存器的值
    regval = GPGDAT;
    key_vals[3] = (regval & (0x1 << 3)) ? 1 : 0; 
    key_vals[0] = (regval & (0x1 << 11)) ? 1 : 0; 

    // 将键值返回到用户空间
    copy_to_user(buf, key_vals, size);

    return sizeof(key_vals);
}
static struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = keys_open,
    .read = keys_read,
};

static int keys_init(void)
{
    major = register_chrdev(0, DEVICE_NAME, &fops);
    if (major < 0)
    {
        printk(DEVICE_NAME " can't register major number.\n");
        return major;
    }

    keys_class = class_create(THIS_MODULE, "keys_class");
    if (IS_ERR(keys_class))
        return PTR_ERR(keys_class);
    // 2. 在class里边创建一个设备叫xxx,然后mdev自动创建设备节点/dev/xxx
    //  在/dev目录下创建相应的设备节点,

        keys_class_dev = class_device_create(keys_class, NULL, MKDEV(major, 0), NULL, "keys_node"); 
        if (unlikely(IS_ERR(keys_class_dev)))
            return PTR_ERR(keys_class_dev); 

    gpfcon = (volatile unsigned long*)ioremap(0x56000050, 16);
    gpfdat = gpfcon + 1;
    gpgcon = (volatile unsigned long*)ioremap(0x56000060, 16);
    gpgdat = gpgcon + 1;

    printk(DEVICE_NAME " device initialized successfully...\n\n");

    return 0;
}

static void keys_exit(void)
{
    // 对应卸载
    unregister_chrdev(major, DEVICE_NAME);

    class_device_unregister(keys_class_dev); 
    class_destroy(keys_class);

    iounmap(gpfcon);
    iounmap(gpgcon);
}

module_init(keys_init);
module_exit(keys_exit);
MODULE_LICENSE("GPL");

2. Makefile

KERN_DIR := /home/xxxxx/Desktop/韦东山/system/linux-2.6.22.6
PWD := $(shell pwd)

obj-m := keys_query.o

all:
	make -C $(KERN_DIR) M=$(PWD) modules CROSS_COMPILE=arm-linux- ARCH=arm
clean:
	make -C $(KERN_DIR) M=$(PWD) clean

3. 用户代码

#include <fcntl.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    int fd;
    int cnt = 0;
    unsigned char key_vals[4];
    
    if (argc != 1)
    {
        printf("No args required.\n\n");
        return 0;
    }

    fd = open("/dev/keys_node", O_RDWR);
    if (fd < 0)
    {
        printf("can't open '/dev/keys_node'.\n");
        return 0;
    }
    printf("Waiting press the keys, will print xxxx.\n\n");
    while(1)
    {
        read(fd, key_vals, sizeof(key_vals));
        if (!key_vals[0] || !key_vals[1] || !key_vals[2] || !key_vals[3])
            printf("%04d key pressed, the value is: %d %d %d %d\n\n", \
                    cnt++, key_vals[0], key_vals[1], key_vals[2], key_vals[3]);
    }
    return 0;
}

4. 加载内核模块,运行用户程序,后台用户程序,查看资源情况

加载内核驱动,
在这里插入图片描述
后台运行用户程序xxx &,再回车一下,
在这里插入图片描述
查看资源占用情况top,查询方法检测按键,资源被占完了,
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值