一、hello驱动程序
编程过程当中,注意参考内核的历程。
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
/*1、确定主设备号*/
static int major = 0;
static char kernel_buf[1024];
static struct class *hello_class;
#define MIN(a,b) (a < b ? a : b)
static ssize_t hello_drv_read (struct file *, char __user *, size_t, loff_t *);
static ssize_t hello_drv_write (struct file *, const char __user *, size_t, loff_t *);
static int hello_drv_open (struct inode *, struct file *);
static int hello_drv_close (struct inode *, struct file *);
/*2、定义自己的file_operations结构体*/
static const struct file_operations hello_drv_fops = {
.owner = THIS_MODULE,
.open = hello_drv_open,
.read = hello_drv_read,
.write = hello_drv_write,
.release = hello_drv_close,
};
/*3、实现对应的open、read、write等函数,填入file_operations结构体内*/
static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *off)
{
int err;
printk("%s %s line %d\n",__FILE__, __FUNCTION__, __LINE__);
err = copy_to_user(buf, kernel_buf, MIN(1024, size));
return MIN(1024, size);
}
static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *off)
{
printk("%s %s line %d\n",__FILE__, __FUNCTION__, __LINE__);
copy_from_user(kernel_buf, buf, MIN(1024, size));
return MIN(1024, size);
}
static int hello_drv_open (struct inode *node, struct file *file)
{
printk("%s %s line %d\n",__FILE__, __FUNCTION__, __LINE__);
return 0;
}
static int hello_drv_close (struct inode *node, struct file *file)
{
printk("%s %s line %d\n",__FILE__, __FUNCTION__, __LINE__);
return 0;
}
/*4、吧file_operations结构体告诉内核:注册驱动程序*/
/*5、谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数*/
static int __init hello_init(void)
{
int err;
printk("%s %s line %d\n",__FILE__, __FUNCTION__, __LINE__);
major = register_chrdev(0, "hello", &hello_drv_fops);
//自动创建设备节点
hello_class = class_create(THIS_MODULE, "hello_class");
err = PTR_ERR(hello_class);
if (IS_ERR(hello_class))
{
unregister_chrdev(major,"hello");
return -1;
}
device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");// /dev/hello
return 0;
}
/*6、有入口函数就有出口函数:卸载驱动时就会去调用这个出口函数*/
static void __exit hello_exit(void)
{
printk("%s %s line %d\n",__FILE__, __FUNCTION__, __LINE__);
device_destroy(hello_class, MKDEV(major, 0));
class_destroy(hello_class);
unregister_chrdev( major, "hello");
}
/*7、其它完善:提供设备信息,自动创建设备节点*/
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tanzhenwen");
二、测试程序
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
/*
* ./hello_drv_test -w abc
* ./hello_drv_test -r
*/
int main(int argc, char *argv[])
{
int fd;
char buf[1024];
int len;
/*1、判断参数*/
if(argc < 2)
{
printf("Usage: %s -w <string>\n",argv[0]);
printf(" %s -r\n",argv[0]);
return -1;
}
/*2、打开文件 */
fd = open("/dev/hello", O_RDWR); //可读可写
if(fd == -1)
{
printf("can not open file /dev/hello\n");
return -1;
}
/* 写文件或者读文件 */
if((0 == strcmp(argv[1],"-w")) && (argc == 3))
{
len = strlen(argv[2]) + 1;
len = len < 1024 ? len : 1024;
write(fd, argv[2], len);
}
else
{
len = read(fd,buf,1024);
buf[1023] = '\0';
//
flush();
printf("APP read: %s\n", buf);
flush();
}
close(fd);
return 0;
}
三、Makefile编写
KERN_DIR = /home/book/100ask_stm32mp157_pro-sdk/Linux-5.4
all:
make -C $(KERN_DIR) M=`pwd` modules
$(CROSS_COMPILE)gcc -o hello_drv_test hello_drv_test.c
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
rm -f hello_drv_test
obj-m += hello_drv.o
四、测试
开发板IP:192.168.124.29;虚拟机IP:192.168.124.30
在虚拟机上设置nfs共享目录/home/book/nfs_rootfs,将驱动程序及测试程序拷贝至该目录下。
开发板上执行挂载命令:
mount -t nfs -o nolock 192.168.124.30:/home/book/nfs_rootfs /mnt
在开发板上执行
insmod insmod hello_drv.ko
./hello_drv_test -w testtesttesttest
./hello_drv_test -r
在开发板上通过cat /proc/device可以查看所有设备的设备号;lsmod可以查看相关驱动装载信息;ls /dev/hello -al 可以查看hello设备的设备号等信息