一、专栏介绍
本专栏内容是记录博主在学习深圳百问网科技有限公司韦东山老师开设的《驱动入门实验班》课程过程中,博主编写、调试、运行在开发板上的课程中涉及的所有驱动试验项目,连载。
课程链接(免费):【Linux驱动入门实验班-B站】 https://www.bilibili.com/video/BV1XK411D7wK/?p=14&share_source=copy_web&vd_source=1bef10f645d499b8efc7d90d0814f719
官方代码仓库(开源):https://e.coding.net/weidongshan/linux_course/linux_basic_develop.git
硬件:100ASK_IMX6ULL_PRO开发板,芯片:NXP IMX6ULL,架构:Cortex-A7 单核。有兴趣可搜索百问网官方网站获取详情。
版权:本篇中代码版权属于韦东山老师。
二、 项目介绍
简单字符设备char_device驱动程序:
-
构造file_operations结构体
-
在里面填充open/read/write/ioctl成员
-
-
注册file_operations结构体
-
int major = register_chrdev(0, "name", &fops);
-
-
入口函数:调用register_chrdev
-
出口函数:调用unregister_chrdev
-
辅助信息:
-
mknod命令创建设备文件,后续用代码实现
-
三、代码
3.1 驱动代码(内核态)
/*
*Copyright (c)2024, CSDN
*All Rights Reserved.
*文件名称: hello_drv.c
*作者:孙家明
*完成日期: 2024.3.3日
*版本号:V1.0
*项目描述:创建一个简单字符设备文件,内核态下实现对该设备的典型访问操作:open/close/read/write,用户态下编写测试代码实现前述操作。
*项目输出: open/close/read/write每个函数被调用时都会有printk打印。
*/
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/uio.h>
#include <linux/uaccess.h>
#include <linux/module.h>
/*主设备号*/
static unsigned int g_hello_major = 0;
static ssize_t hello_read (struct file *filp, char __user *buf, size_t size, loff_t *offset)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return size;
}
static ssize_t hello_write (struct file *filp, const char __user *buf, size_t size, loff_t *offset)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return size;
}
static int hello_open (struct inode *node, struct file *filp)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
static int hello_release (struct inode *node, struct file *flip)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
/* 1. create file operations */
static const struct file_operations hello_drv = {
.owner = THIS_MODULE,
.read = hello_read,
.write = hello_write,
.open = hello_open,
.release = hello_release
};
/* 2. register chrdey */
/* 3. entry function */
static int __init hello_init(void)
{
g_hello_major = register_chrdev(0, "100ask_hello", &hello_drv);
return 0;
}
/* 4. exit function */
static void __exit hello_exit(void)
{
unregister_chrdev(g_hello_major , "100ask_hello");
return;
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL v2");
3.2 驱动测试代码(用户态)
/*
*Copyright (c)2024, CSDN
*All Rights Reserved.
*文件名称: hello_drv_test.c
*作者:孙家明
*完成日期: 2024.3.3日
*版本号:V1.0
*项目描述:创建一个简单字符设备文件,内核态下实现对该设备的典型访问操作:open/close/read/write,用户态下编写测试代码实现前述操作。
*项目输出: open/close/read/write每个函数被调用时都会有printk打印。
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
/*
*写 ./hello_test /dev/xxx hello_world
*读 ./hello_test /dev/xxx
*/
#define BUF_LEN 100
int main(int argc, char *argv[])
{
int fd = -1;
int ret = 0;
char buf[BUF_LEN] = {0};
if(argc < 2)
{
printf("Usage: ");
printf("%s <dev> [string]\n", argv[0]);
return -1;
}
/*open*/
fd = open(argv[1], O_RDWR);
if(0 > fd)
{
printf("cannot open file: %s, err!\n", argv[1]);
return -1;
}
if(argc == 3)
{
/*write*/
ret = write(fd, argv[2], strlen(argv[2])+1);
if(0 > ret)
{
printf("cannot write file: %s, err!\n", argv[1]);
return -1;
}
}
else
{
/*read*/
ret = read(fd, buf, BUF_LEN);
if(0 > ret)
{
printf("cannot read file: %s, err!\n", argv[1]);
return -1;
}
buf[BUF_LEN-1] = '0';
}
/*close*/
close(fd);
return 0;
}
四、试验步骤及结果
/*加载模块*/
[root@100ask:/mnt/dri_labclass/01_hello_drv]# insmod hello_drv.ko
[ 830.574370] hello_drv: loading out-of-tree module taints kernel.
/*显示模块*/
[root@100ask:/mnt/dri_labclass/01_hello_drv]# lsmod
Module Size Used by
hello_drv 2152 0
/*创建设备文件*/
[root@100ask:/mnt/dri_labclass/01_hello_drv]# mknod /dev/hellodev c 240 0
[root@100ask:/mnt/dri_labclass/01_hello_drv]# ll /dev/hellodev
crw-r--r-- 1 root root 240, 0 Jan 1 00:40 /dev/hellodev
/*写操作*/
[root@100ask:/mnt/dri_labclass/01_hello_drv]# ./hello_drv_test /dev/hellodev sjmsjm
[ 2862.371308] /home/book/nfs_rootfs/dri_labclass/01_hello_drv/hello_drv.c hello_open 41
[ 2862.379990] /home/book/nfs_rootfs/dri_labclass/01_hello_drv/hello_drv.c hello_write 35
[ 2862.390021] /home/book/nfs_rootfs/dri_labclass/01_hello_drv/hello_drv.c hello_release 46
/*读操作*/
[root@100ask:/mnt/dri_labclass/01_hello_drv]#
[root@100ask:/mnt/dri_labclass/01_hello_drv]# ./hello_drv_test /dev/hellodev
[ 2870.867199] /home/book/nfs_rootfs/dri_labclass/01_hello_drv/hello_drv.c hello_open 41
[ 2870.875827] /home/book/nfs_rootfs/dri_labclass/01_hello_drv/hello_drv.c hello_read 29
[ 2870.884006] /home/book/nfs_rootfs/dri_labclass/01_hello_drv/hello_drv.c hello_release 46
/*卸载模块*/
[root@100ask:/mnt/dri_labclass/01_hello_drv]# rmmod hello_drv.ko