区分不同的设备驱动
设备文件名 设备号:主设备号,次设备号驱动链表
管理不同设备驱动程序 添加:编写完驱动程序,加载到内核 查找:调用驱动程序 删除 驱动插入链表的顺序由设备号检索提示:printk为内核打印函数,可以通过dmesg查看内核信息
内核驱动框架基本
a.驱动代码编写,参考pin4driver2.c b.内核驱动编译 a1.把驱动代码拷贝到drivers/char a2.修改Makefile(obj-m +=pin4driver2.o),告诉编译器,要编译的驱动文件 a3.ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- KERNEL=kernel7 make modules c.编译成功生成pin4driver2.ko d.将驱动文件拷贝到树莓派开发板 e.sudo insmod pin4driver2.ko(删除驱动可用 rmmod pin4driver2)---装载内核驱动,可通过查看dev下查看对应的设备文件 :装载驱动的时候会调用驱动源码的pin4_drv_init f.sudo chmod 666 pin4-----所有用户均可读写的权限结合树莓派芯片手册配置寄存器驱动GPIO
GPFSEL0 GPIO Function Select 0 ----功能选择 输出/输入 32位 GPSET0 GPIO Pin Output Set 1-------输出1 0 = no effect 1 = Set GPIO pin n----根据引脚编号决定哪一位写1 GPCLR0 GPIO Pin Output Clear 0-----清0 0 = no effect 1 = Clear GPIO pin n----根据引脚编号决定哪一位写1pin4引脚驱动程序
#include <linux/fs.h> //file_operations声明 #include <linux/module.h> //module_init,module_exit声明 #include <linux/init.h> //_init,_exit声明 #include <linux/device.h> //class,device声明 #include <linux/uaccess.h> //copy_from_user的头文件 #include <linux/types.h> //设备号,dev_t类型声明 #include <asm/io.h> //ioremap iounmap的头文件 static struct class *pin4_class; static struct device *pin4_class_dev; static dev_t devno; //设备号 static int major = 231; //主设备号 static int minor = 0; //次设备号 static char *module_name = "pin4"; //模块名 volatile unsigned int* GPFSEL0 = NULL; volatile unsigned int* GPFSET1 = NULL; volatile unsigned int* GPFCLR0 = NULL; //led_open函数 static int pin4_open(struct inode *inode,struct file *file){ printk("pin4_open\n"); *GPFSEL0 &= ~(0x6 << 12); *GPFSEL0 |= (0x1 << 12); return 0; } //led_write函数 static size_t pin4_write(struct file *file,const char __user *buf,size_t count,loff_t *ppos){ int userCmd; printk("pin4_write\n"); copy_from_user(&userCmd,buf,count); printk("get value\n"); if(userCmd == 1){ *GPFSET1 |= (0x1 << 4); }else if(userCmd == 0){ *GPFCLR0 |= (0x1 << 4); }else{ printk("undo\n"); } return 0; } static struct file_operations pin4_fops = { .owner = THIS_MODULE, .open = pin4_open, .write = pin4_write, }; int __init pin4_drv_init(void) //真实驱动入口 { int ret; printk("insmod success\n"); devno = MKDEV(major,minor);//创建设备号 ret = register_chrdev(major,module_name,&pin4_fops);//注册驱动,把驱动加到内核链表中 pin4_class = class_create(THIS_MODULE,"myfirstdemo");//让代码在dev自动生成设备 pin4_class_dev = device_create(pin4_class,NULL,devno,NULL,module_name);//创建设备文件 GPFSEL0 = (volatile unsigned int*)ioremap(0x3f200000,4);//物理地址转虚拟地址,io口寄存器映射成普通寄存单元 GPFSET1 = (volatile unsigned int*)ioremap(0x3f20001c,4); GPFCLR0 = (volatile unsigned int*)ioremap(0x3f200028,4); return 0; } void __exit pin4_drv_exit(void) { iounmap(GPFSEL0); iounmap(GPFSET1); iounmap(GPFCLR0); device_destroy(pin4_class,devno); class_destroy(pin4_class); unregister_chrdev(major,module_name);//卸载驱动 } module_init(pin4_drv_init);//入口,内核加载该驱动的时候,这个宏被调用 module_exit(pin4_drv_exit); MODULE_LICENSE("GPL v2");测试程序
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int main() { int fd; int cmd; fd = open("/dev/pin4",O_RDWR); if(fd < 0){ printf("open failed\n"); }else{ printf("open success\n"); } printf("please input 0/1:"); scanf("%d",&cmd); printf("cmd = %d\n",cmd); fd = write(fd,&cmd,1); return 0; }执行程序后,可通过gpio readall来查看引脚功能变化