Linux字符驱动设备--学习笔记
第一步:编写globalvar.c文件。主要包括:open、release、read、write、init和exit方法的编写; 第二步:编写Makefile文件,然后编译globalvar.c; 第三步:insmod加载模块,并生成设备节点mknod。(此步有两种方法); 第四步:编写测试文件test.c并编译成a.out后即可进行设备的读写测试。 在此,希望各位读者不要直接复制我的代码,至少按照我的代码敲一遍,关键是理解才行。我们的学习才刚刚开始,与诸位共勉!!! ### Linux字符驱动设备学习笔记详解 #### 一、概述 在Linux系统中,所有的设备都被抽象成文件形式,用户可以通过类似文件操作的方式来控制硬件设备。根据数据传输方式的不同,Linux设备主要分为两类:字符设备和块设备。字符设备通常用于处理以字符流形式的数据输入/输出,例如串行端口或键盘;而块设备则是以固定大小的数据块来传输数据,如硬盘或固态硬盘。 本文档基于一个简单的字符设备示例——`globalvar`来进行讲解,该设备的核心功能是通过内核模块实现对一个全局变量`int global_var`的管理。通过一系列步骤,我们将了解如何编写驱动程序,编译模块,以及如何使用该设备。 #### 二、准备工作 1. **创建globalvar.c文件** 在终端中,首先进入工作目录,并使用文本编辑器创建`globalvar.c`文件。以下是`globalvar.c`文件的主要代码框架: ```c #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/uaccess.h> MODULE_LICENSE("GPL"); int globalvar_open(struct inode *, struct file *); int globalvar_release(struct inode *, struct file *); ssize_t globalvar_read(struct file *, char *, size_t, loff_t *); ssize_t globalvar_write(struct file *, const char *, size_t, loff_t *); int dev_major = 0; int dev_minor = 0; struct file_operations globalvar_fops = { .owner = THIS_MODULE, .open = globalvar_open, .release = globalvar_release, .read = globalvar_read, .write = globalvar_write, }; struct globalvar_dev { int global_var; // 设备变量或者称为设备内存(只有4个字节) struct cdev cdev; // 内核中表示字符设备的结构 }; struct globalvar_dev *my_dev; static void __exit globalvar_exit(void) { dev_t devno = MKDEV(dev_major, dev_minor); cdev_del(&my_dev->cdev); kfree(my_dev); unregister_chrdev_region(devno, 1); printk("globalvar unregistersuccess\n"); } static int __init globalvar_init(void) { int ret, err; if (dev_major) { dev_t devno = MKDEV(dev_major, dev_minor); ret = register_chrdev_region(devno, 1, "globalvar"); } else { ret = alloc_chrdev_region(&devno, dev_minor, 1, "globalvar"); dev_major = MAJOR(devno); } if (ret < 0) { printk("globalvar register failure\n"); globalvar_exit(); return ret; } else { printk("globalvar register success\n"); } my_dev = kmalloc(sizeof(struct globalvar_dev), GFP_KERNEL); ``` 2. **定义关键函数** - **`globalvar_open()`**:当设备被打开时调用。在此函数中可以执行任何必要的初始化操作。 - **`globalvar_release()`**:当设备关闭时调用。通常用于清理资源。 - **`globalvar_read()`**:当从设备读取数据时调用。 - **`globalvar_write()`**:当向设备写入数据时调用。 3. **初始化和退出处理** - **`globalvar_init()`**:这是模块初始化函数,负责设备号的注册以及其他初始化工作。 - **`globalvar_exit()`**:模块卸载时调用此函数,用于清理已分配的资源。 #### 三、编译模块 1. **编写Makefile文件** Makefile文件用于指定如何编译和安装模块。一个简单的Makefile可能如下所示: ``` obj-m += globalvar.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean ``` 2. **编译globalvar.c** 使用以下命令编译模块: ```bash make ``` #### 四、加载模块及创建设备节点 1. **加载模块** 使用`insmod`命令加载模块: ```bash sudo insmod globalvar.ko ``` 2. **创建设备节点** 可以使用`mknod`命令创建设备节点,有以下两种方法: - 直接指定设备号: ```bash sudo mknod /dev/globalvar c 10 0 ``` - 动态获取设备号: ```bash sudo mknod /dev/globalvar c $(cat /sys/class/misc/globalvar/dev) ``` #### 五、编写测试程序 1. **编写test.c** 创建一个简单的C程序来测试字符设备的功能。例如,可以编写一个简单的程序来读取和写入全局变量`global_var`。 2. **编译test.c** 使用`gcc`编译`test.c`,生成可执行文件`a.out`: ```bash gcc -o a.out test.c ``` 3. **测试字符设备** 运行`a.out`,根据程序设计,它应该能够读取和修改`global_var`的值,并显示结果。 #### 六、总结 本文档详细介绍了如何创建和使用一个简单的Linux字符设备。通过以上步骤,我们不仅学习了如何编写内核模块来管理硬件资源,还掌握了如何在用户空间通过C语言程序与内核交互。对于初学者来说,这是一个很好的起点,通过实践加深理解是非常重要的。随着经验的积累,你可以尝试更复杂的设备驱动程序,进一步提高自己的技能水平。
- 粉丝: 42
- 资源: 6
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助