树莓派最简单的字符设备驱动框架

实现的功能

通过这个驱动可以实现文件的打开,写等操作,例如,控制gpio,
这里先写基础的结构

整体框架

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
 
static struct class *firstdrv_class;
static struct cdev firstdrv_class_dev;
dev_t major;
 
static int first_drv_open(struct inode *inode, struct file *file)
{
return 0;
}
 
  
static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
return 0;
}
 
  
static struct file_operations first_drv_fops = {
.owner = THIS_MODULE,
.open = first_drv_open,
.write = first_drv_write,
};
 
  
static int first_drv_init(void)
{
return 0;
}
 
  
static void first_drv_exit(void)
{
}
 
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_DESCRIPTION(“RPi First Drv”);
MODULE_AUTHOR(“namewei”);
MODULE_LICENSE(“GPL”);

整体的框架如上
有一些是固定的,记住就好了。
要改的就是file_operations里面的(如实现open,write等操作)
然后再进行模块加载的初始化module_init(first_drv_init);        /* 在insmod 时候执行的 */
和卸载模块的函数module_exit(first_drv_exit);            /
*在rmmod 时候执行的 */

第一个基本的字符驱动

填充module_init()函数

static int first_drv_init(void)
{
    /* cdev /
cdev_init(&firstdrv_class_dev, &first_drv_fops);
alloc_chrdev_region(&major, 0, 1, “first_drv”);
cdev_add(&firstdrv_class_dev,major, 1);
    /
注册class */
firstdrv_class = class_create(THIS_MODULE, “my_first_drv”);
device_create(firstdrv_class, NULL, major, NULL,“first_drv”);
      
printk(“init successful\n”);
return 0;
}

在调用cdev_add()函数向系统注册字符设备之前,应首先调用register_chrdev_region()或 alloc_chrdev_region()函数向系统申请设备号
register_chrdev_region()函数用于已知起始设备的设备号的情况,而alloc_chrdev_region()用于设 备号未知,向系统动态申请未被占用的设备号的情况,函数调用成功之后,会把得到的设备号放入第一个 参数dev中。alloc_chrdev_region()相比于register_chrdev_region()的优点在于它会自动避开设备号重复 的冲突。

填充module_exit()函数

static void first_drv_exit(void)
{
device_destroy(firstdrv_class,major);
class_destroy(firstdrv_class);
cdev_del(&firstdrv_class_dev);
unregister_chrdev(major, “first_drv”);
printk(“exit first_drv\n”);
}

这个步骤就没有什么好记的,跟init函数反着来。从下到上的unregister和destroy

填充open wirte 函数

static int first_drv_open(struct inode *inode, struct file *file)
{
printk(“open\n”);
return 0;
}

static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
printk(“write\n”);
return 0;
}

Makefile

ifneq ($(KERNELRELEASE),)
obj-m := first_drv.o

else
PWD :=$(shell pwd)
KDIR := /work/linux-4.4
all:
make -C ( K D I R ) M = (KDIR) M= (KDIR)M=(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
clean:
rm -f *.ko *.o *.mod.o *.mod.c .symvers modul

endif

然后make一下,转移到树莓派
先执行一下

tail -f /var/log/syslog

然后开启另一个终端

insmod first_drv.ko

树莓派最简单的字符设备驱动框架_第1张图片
你就可以看到最后的init sucessful
然后新建测试代码

命名为first_test.c

这个代码是之前在2440上写的稍微改动一下,有些东西是多余的。不过没影响
树莓派最简单的字符设备驱动框架_第2张图片

gcc first_test.c -o first_test

然后就执行

./first_test

在syslog中就会看到open
在这里插入图片描述
看看测试代码就知道,因为没有带参数,就没有执行到write
接着测试write
输入

./first_test on

在这里插入图片描述
然后

rmmod first_drv

在这里插入图片描述

你可能感兴趣的:(树莓派驱动)