button_device.c
#include <linux/module.h> #include <linux/init.h> #include <linux/platform_device.h> static void button_release(struct device *dev) { printk("%s\n", __FUNCTION__); return; } struct resource button_resource[] = { { .start = 0x20c406c, .end = 0x20c406c+3, // IORESOURCE_MEM必须要加上end,不然会报错 .name = "CCGR", .flags = IORESOURCE_MEM, }, { .start = 0x229000c, .end = 0x229000c+3, .name = "SW_MUX_CTL", .flags = IORESOURCE_MEM, }, { .start = 0x2290050, .end = 0x2290050+3, .name = "SW_PAD_CTL", .flags = IORESOURCE_MEM, }, { .start = 0x20ac004, .end = 0x20ac004+3, .name = "GDIR", .flags = IORESOURCE_MEM, }, { .start = 0x20ac008, .end = 0x20ac008+3, .name = "PSR", .flags = IORESOURCE_MEM, }, { .start = 1, .end = 0, .name = "pin", .flags = IORESOURCE_IRQ, }, { .start = 30, .end = 0, .name = "clock_offset", .flags = IORESOURCE_IRQ, }, }; struct platform_device button_device = { .name = "my_button", // 这个名字必须要和设备资源结构体里面的name一致,不然这两个模块匹配不了 .id = -1, .num_resources = ARRAY_SIZE(button_resource), .resource = button_resource, .dev = { .release = button_release, }, }; // 入口函数 static int button_platform_device_init(void) { int ret = 0; printk("%s\n", __FUNCTION__); ret = platform_device_register(&button_device); // 注册设备信息 return ret; } // 出口函数 static void button_platform_device_exit(void) { printk("%s\n", __FUNCTION__); platform_device_unregister(&button_device); } module_init(button_platform_device_init); module_exit(button_platform_device_exit); MODULE_LICENSE("GPL");
button_driver.c
#include <linux/module.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/miscdevice.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/mutex.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/stat.h> #include <linux/init.h> #include <linux/device.h> #include <linux/tty.h> #include <linux/kmod.h> #include <linux/gfp.h> #include <asm/mach/map.h> #include <linux/platform_device.h> #include <asm/io.h> static u32 *vi_ccgr; static u32 *vi_mux_ctl; static u32 *vi_pad_ctl; static u32 *vi_gdir; static u32 *vi_psr; static u32 pin; static u32 clock_offset; static int major = 0; static struct class *button_class; static ssize_t button_drv_read(struct file * file, char __user * buf, size_t size, loff_t *offset) { char status = 0; int ret; if (*vi_psr & (1<<pin)) { //printk("按键点击了\n"); status = 1; } else { status = 0; } ret = copy_to_user(buf, &status, 1); return 1; } static ssize_t button_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) { printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); return 0; } static int button_drv_open(struct inode *node, struct file *file) { // 初始化设备 *(vi_ccgr) |= (3<<clock_offset); *(vi_mux_ctl) &= ~0xf; *(vi_mux_ctl) |= 0x5; *(vi_gdir) &= ~(1<<pin); printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); return 0; } static int button_drv_close(struct inode *node, struct file *file) { printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); return 0; } static struct file_operations button_opr = { .open = button_drv_open, .release = button_drv_close, .read = button_drv_read, .write = button_drv_write, }; static int button_probe(struct platform_device *pdev) { int i = 0; struct resource *res; u32 ph_addr[5]; int err; // 获取资源 for (i=0;i<5;i++) { res = platform_get_resource(pdev, IORESOURCE_MEM, i); if (res == NULL) { printk("not get resource\n"); return -1; } ph_addr[i] = res->start; } res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); pin = res->start; res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); clock_offset = res->start; // 内存映射 vi_ccgr = ioremap(ph_addr[0], 4); vi_mux_ctl = ioremap(ph_addr[1], 4); vi_pad_ctl = ioremap(ph_addr[2], 4); vi_gdir = ioremap(ph_addr[3], 4); vi_psr = ioremap(ph_addr[4], 4); // 完成设备注册的操作 // register_chrdev() class_create() device_create() major = register_chrdev(0, "my_button", &button_opr); button_class = class_create(THIS_MODULE, "button_class"); err = PTR_ERR(button_class); if (IS_ERR(button_class)) { unregister_chrdev(major, "my_button"); return -1; } device_create(button_class, NULL, MKDEV(major, 0), NULL, "my_button"); printk("%s\n", __FUNCTION__); return 0; } static int button_remove(struct platform_device *pdev) { printk("%s\n", __FUNCTION__); // 释放虚拟内存 iounmap(vi_ccgr); iounmap(vi_mux_ctl); iounmap(vi_pad_ctl); iounmap(vi_gdir); iounmap(vi_psr); // 完成设备取消注册的操作 device_destroy(button_class, MKDEV(major,0)); class_destroy(button_class); unregister_chrdev(major, "my_button"); printk("%s\n", __FUNCTION__); return 0; } struct platform_driver button_driver = { .probe = button_probe, .remove = button_remove, .driver = { .name = "my_button", }, }; // 入口函数 static int button_platform_driver_init(void) { int ret = 0; printk("%s\n", __FUNCTION__); ret = platform_driver_register(&button_driver); // 注册设备信息 return ret; } // 出口函数 static void button_platform_driver_exit(void) { printk("%s\n", __FUNCTION__); platform_driver_unregister(&button_driver); // 注册设备信息 } module_init(button_platform_driver_init); module_exit(button_platform_driver_exit); MODULE_LICENSE("GPL");
button_test.c
#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> int main(int argc, char **argv) { int fd; char status = 0; int ret = 0; int bnt = 0; if (argc !=2 ) { printf("Usage: %s <dev-path>\n", argv[0]); return -1; } fd = open(argv[1], O_RDWR); if (fd < 0) { perror("open error"); return -1; } while(1) { ret = read(fd, &status, 1); if (ret < 0) { perror("read error"); return -1; } else if (ret == 1 && status == 1) { printf("button %d\n", bnt++); } } return 0; }
Makefile
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- // 该参数与你的交叉编译工具有关 export ARCH CROSS_COMPILE KERN_DIR = /home/hxd/workdir/ebf_linux_kernel_6ull_depth1/build_image/build // 该目录与你的编译好的内核目录有关 all: make -C $(KERN_DIR) M=`pwd` modules $(CROSS_COMPILE)gcc -o button_test button_test.c clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order rm -f button_test obj-m += button_device.o button_driver.o