通过这个驱动可以实现文件的打开,写等操作,例如,控制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 时候执行的 */
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()的优点在于它会自动避开设备号重复 的冲突。
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
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;
}
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
你就可以看到最后的init sucessful
然后新建测试代码
命名为first_test.c
这个代码是之前在2440上写的稍微改动一下,有些东西是多余的。不过没影响
gcc first_test.c -o first_test
然后就执行
./first_test
在syslog中就会看到open
看看测试代码就知道,因为没有带参数,就没有执行到write
接着测试write
输入
./first_test on
rmmod first_drv