写这个驱动的目的是作为后面字符设备的模板,这里采用最原始的方法,其实写字符设备有很多框架可以用,例如可以使用register_chrdev_region, 也可以使用platform,最简单的还可以使用misc。这里采用register_chrdev_region的方式,其他两种方式这里不赘述。
先看Makefile
TARGET := hello
obj-m += $(TARGET).o
ROOTFS = /home/flinn/tmp/rootfs
KERNEL = /home/flinn/tiny4412-SDK/linux-4.19.27
all:
make -C $(KERNEL) M=`pwd` modules
clean:
make -C $(KERNEL) M=`pwd` clean
install:
#make -C $(KERNEL) M=`pwd` modules_install INSTALL_MOD_PATH=$(ROOTFS)
sudo cp $(TARGET).ko $(ROOTFS)
这里我使用绝对路径,方便我自己使用而已。
hello.c
/*
* hello driver on linux-4.19.27(without dt)
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/gfp.h>
#include <linux/cdev.h>
static struct cdev *cdev= NULL;
static dev_t dev;
static int major = 0;
static char *name = "hello";
static struct class *hello_class = NULL;
static int hello_open (struct inode *inode, struct file *file)
{
return 0;
}
static int hello_close (struct inode *inode, struct file *file)
{
return 0;
}
const struct file_operations fops =
{
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_close,
};
static int hello_drv_init(void)
{
int ret = 0;
printk(KERN_INFO "hello init.\n");
if(major)
{
dev = MKDEV(major,0);
ret = register_chrdev_region(dev,1,name);
}
else
{
ret = alloc_chrdev_region(&dev, 0, 1, name);
major = MAJOR(dev);
}
if(ret < 0)
{
printk(KERN_ERR "register fail. major : %d \n", major);
return ret;
}
cdev = cdev_alloc();
if(!cdev)
{
printk(KERN_ERR "cdev alloc fail.\n");
return -1;
}
cdev_init(cdev,&fops);
cdev->owner = THIS_MODULE;
cdev->ops = &fops;
cdev_add(cdev, dev,1);
hello_class = class_create(THIS_MODULE, "hello");
ret = PTR_ERR(hello_class);
if (IS_ERR(hello_class))
{
cdev_del(cdev);
unregister_chrdev_region(dev,1);
return -1;
}
return 0;
}
static void hello_drv_exit(void)
{
printk(KERN_INFO "hello exit.\n");
class_destroy(hello_class);
cdev_del(cdev);
unregister_chrdev_region(dev,1);
}
module_init(hello_drv_init);
module_exit(hello_drv_exit);
MODULE_LICENSE("GPL");
比较好的方法是把static变量用结构体封装一下,看起来更紧凑些。
至于驱动加载:
insmod hello.ko # load
rmmod hello # remove