一、static int button_init(void) 入口函数作用:
1、major = register_chrdev(0, DEVICE_NAME, &button_ops);注册字符设备
2、button_class = class_create(THIS_MODULE, "button");创建类
3、button_dev_class = class_device_create(button_class, NULL, MKDEV(major, 0), NULL, "my_button"); /* /dev/my_button */ 创建设备文件
4、 gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);ioremap函数虚拟add映射
button_exit出口函数 作用与入口函数类似;
二、static int button_open (struct inode *inode, struct file *filep) 配置输入引脚
三、ssize_t button_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)读取引脚电平并由copy_to_user(buf, key_vals, sizeof(key_vals))函数上传至用户层读函数
my_button.c
#include <asm/arch/regs-gpio.h> #include <asm/hardware.h> #define DEVICE_NAME "mybutton" /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */ static struct class *button_class; static struct class_device *button_dev_class; int major; volatile unsigned long *gpfcon; volatile unsigned long *gpfdat; volatile unsigned long *gpgcon; volatile unsigned long *gpgdat; /* 应用程序对设备文件/dev/xxx 执行open(...)时, * 就会调用button_open函数 */ static int button_open (struct inode *inode, struct file *filep) { /* 配置GPF0,2为输入引脚 */ //1、对应位置为0 2 、相应位配置 *gpfcon &= ~((0x3<<(0*2)) | (0x3<<(2*2))); /* 配置GPG3,11为输入引脚 */ *gpgcon &= ~((0x3<<(3*2)) | (0x3<<(11*2))); return 0; } ssize_t button_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { /* 返回4个引脚的电平 */ unsigned char key_vals[4]; int regval; if (size != sizeof(key_vals)) return -EINVAL; regval=*gpfdat; key_vals[0] =(regval&(1<<0))?1:0; key_vals[1] =(regval&(1<<2))?1:0; /* 读GPG3,11 */ regval = *gpgdat; key_vals[2] = (regval & (1<<3)) ? 1 : 0; key_vals[3] = (regval & (1<<11)) ? 1 : 0; copy_to_user(buf, key_vals, sizeof(key_vals)); return sizeof(key_vals); } /* 这个结构是字符设备驱动程序的核心 * 当应用程序操作设备文件时所调用的open、read、write等函数, * 最终会调用这个结构中指定的对应函数 */ static struct file_operations button_ops= { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = button_open, .read = button_read, }; /* * 执行insmod命令时就会调用这个函数 */ static int button_init(void) { int ret; /* 注册字符设备 * 参数为主设备号、设备名字、file_operations结构; * 这样,主设备号就和具体的file_operations结构联系起来了, * 操作主设备为LED_MAJOR的设备文件时,就会调用s3c24xx_leds_fops中的相关成员函数 * LED_MAJOR可以设为0,表示由内核自动分配主设备号 */ major = register_chrdev(0, DEVICE_NAME, &button_ops); if (major < 0) { printk(DEVICE_NAME " can't register major number number::%d\n",major); return ret; } printk(DEVICE_NAME " initialized1\n"); button_class = class_create(THIS_MODULE, "button"); if (IS_ERR(button_class)) return PTR_ERR(button_class); button_dev_class = class_device_create(button_class, NULL, MKDEV(major, 0), NULL, "my_button"); /* /dev/my_button */ gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16); gpfdat = gpfcon + 1; gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16); gpgdat = gpgcon + 1; return 0; } /* * 执行rmmod命令时就会调用这个函数 */ static void button_exit(void) { class_device_unregister(button_dev_class); class_destroy(button_class); /* 卸载驱动程序 */ unregister_chrdev(major, DEVICE_NAME); iounmap(gpfcon); iounmap(gpgcon); } /* 这两行指定驱动程序的初始化函数和卸载函数 */ module_init(button_init); module_exit(button_exit); /* 描述驱动程序的一些信息,不是必须的 */ MODULE_AUTHOR("http://www.100ask.net");// 驱动程序的作者 MODULE_DESCRIPTION("S3C2410/S3C2440 LED Driver");// 一些描述信息 MODULE_LICENSE("GPL"); // 遵循的协议
test.c
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> int main(int argc,char**argv) { int fd; unsigned char key_vals[4]; int cnt = 0; //1、打开设备 fd = open("/dev/my_button",O_RDWR); if(fd<0) { perror("open fail \n"); return -1; } while(1)//一直再次循环执行,很占用cpu资源 将其后台运行 ./a.out & 然后再执行top 可以看到其占用资源达到99%所以必须将其该井为中断 { read(fd,key_vals, sizeof(key_vals)); if (!key_vals[0] || !key_vals[1] || !key_vals[2] || !key_vals[3]) { printf("%04d key pressed: %d %d %d %d\n", cnt++, key_vals[0], key_vals[1], key_vals[2], key_vals[3]); } } close(fd); return 0; }
#ubuntu的内核源码树,如果要编译在ubuntu中安装的模块就打开这2个 #KERN_VER = $(shell uname -r) #KERN_DIR = /lib/modules/$(KERN_VER)/build # 开发板的linux内核的源码树目录 #KERN_DIR =/lib/modules/2.6.31-14-generic/build KERN_DIR = /home/book/per/kernel/linux-2.6.22.6 #/root/driver/kernel obj-m += my_button.o all: make -C $(KERN_DIR) M=`pwd` modules #cp: # cp *.ko /root/porting_x210/rootfs/rootfs/driver_test .PHONY: clean clean: make -C $(KERN_DIR) M=`pwd` modules clean cp: cp /mnt/hgfs/publicshare/drivers_and_test/my_button/ /home/book/dri/ -rf