Linux字符设备有哪些常见类型及特点

来源:个人站长作者:新加坡程序员头衔:程序员
导读:本期聚焦于小伙伴创作的《Linux字符设备有哪些常见类型及特点》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Linux字符设备有哪些常见类型及特点》有用,将其分享出去将是对创作者最好的鼓励。

Linux字符设备是Linux系统中三类主要设备之一,与块设备、网络设备并列,核心特征是数据以字节流的形式进行顺序读写,不支持像块设备那样的随机寻址访问,常见的键盘、鼠标、串口都属于字符设备范畴。

Linux字符设备有哪些常见类型及特点

Linux字符设备的核心特点

字符设备的核心特性决定了它的适用场景,主要有以下几个特点:

  • 数据读写以字节为单位,按顺序进行,无法跳过中间数据直接访问后续内容
  • 没有缓存机制或者缓存机制非常简单,数据读写通常直接和硬件交互
  • 通过文件系统中的设备节点进行访问,设备节点对应主设备号和次设备号
  • 驱动需要实现file_operations结构体中的相关操作函数,供上层应用调用

常见的Linux字符设备类型

1. 输入类字符设备

这类设备用于接收用户输入,是最常见的一类字符设备,包括键盘、鼠标、触摸屏等。它们的数据输出是连续的事件流,比如按键按下、鼠标移动坐标等,应用层通过读取设备节点获取输入事件。

2. 串口类字符设备

串口设备比如RS232、USB转串口设备等,用于实现串行通信,数据按位顺序传输。这类设备通常用于嵌入式设备调试、外接传感器数据读取等场景,读写操作都是按字节流进行。

3. 音频类字符设备

声卡相关的设备节点大多属于字符设备,比如/dev/dsp、/dev/audio等,用于音频数据的采集和播放。音频数据以连续的字节流形式传输,不支持随机访问某一帧音频数据。

4. 自定义字符设备

开发者在驱动开发中自行注册的字符设备,用于实现特定硬件的访问逻辑,比如自定义的GPIO控制设备、特定的传感器读取设备等。这类设备的主设备号可以动态申请,也可以静态指定。

字符设备驱动的基本开发流程

开发字符设备驱动需要遵循Linux内核的驱动框架,核心步骤如下:

第一步:定义设备结构体

首先需要定义包含cdev结构体的自定义设备结构体,cdev是内核中表示字符设备的核心结构体。

#include <linux/cdev.h>
#include <linux/fs.h>

// 自定义字符设备结构体
struct my_char_dev {
    struct cdev cdev;  // 内核cdev结构体
    int data;          // 自定义设备数据
};

struct my_char_dev *dev; // 设备实例指针

第二步:实现file_operations操作函数

file_operations结构体定义了设备支持的操作,比如打开、读取、写入、释放等,需要根据设备功能实现对应的函数。

// 设备打开函数
static int my_open(struct inode *inode, struct file *filp) {
    // 将设备结构体指针保存到file结构体的私有数据中
    filp->private_data = container_of(inode->i_cdev, struct my_char_dev, cdev);
    return 0;
}

// 设备读取函数
static ssize_t my_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) {
    struct my_char_dev *dev = filp->private_data;
    // 这里实现读取逻辑,将数据拷贝到用户空间
    // copy_to_user(buf, &dev->data, count);
    return count;
}

// 设备写入函数
static ssize_t my_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) {
    struct my_char_dev *dev = filp->private_data;
    // 这里实现写入逻辑,从用户空间拷贝数据
    // copy_from_user(&dev->data, buf, count);
    return count;
}

// 设备操作结构体
static const struct file_operations my_fops = {
    .owner = THIS_MODULE,
    .open = my_open,
    .read = my_read,
    .write = my_write,
};

第三步:注册字符设备

需要申请设备号,初始化cdev结构体,然后将设备添加到内核中。

static int major = 0; // 主设备号,0表示动态申请
static int minor = 0; // 次设备号起始值
static dev_t devno;   // 设备号

static int __init my_char_init(void) {
    int ret;
    // 动态申请主设备号
    ret = alloc_chrdev_region(&devno, minor, 1, "my_char_dev");
    if (ret < 0) {
        return ret;
    }
    major = MAJOR(devno); // 获取分配的主设备号

    // 分配设备结构体内存
    dev = kzalloc(sizeof(struct my_char_dev), GFP_KERNEL);
    if (!dev) {
        unregister_chrdev_region(devno, 1);
        return -ENOMEM;
    }

    // 初始化cdev结构体,绑定操作函数
    cdev_init(&dev->cdev, &my_fops);
    dev->cdev.owner = THIS_MODULE;

    // 添加cdev到内核
    ret = cdev_add(&dev->cdev, devno, 1);
    if (ret) {
        kfree(dev);
        unregister_chrdev_region(devno, 1);
        return ret;
    }
    return 0;
}
module_init(my_char_init);

第四步:注销字符设备

模块卸载时需要释放相关资源,避免内存泄漏。

static void __exit my_char_exit(void) {
    // 删除cdev
    cdev_del(&dev->cdev);
    // 释放设备结构体内存
    kfree(dev);
    // 释放设备号
    unregister_chrdev_region(devno, 1);
}
module_exit(my_char_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("kernel developer");

字符设备与块设备的区别

很多开发者容易混淆字符设备和块设备,两者的核心区别如下:

对比项字符设备块设备
数据读写单位字节流数据块(通常512字节及以上)
访问方式顺序访问,不支持随机寻址支持随机寻址,可直接访问任意块
缓存机制几乎无缓存或缓存简单有复杂的页缓存机制
典型设备键盘、鼠标、串口硬盘、U盘、SSD

了解Linux字符设备的类型和开发流程,是学习Linux驱动开发的基础,开发者可以根据实际需求选择对应的设备类型进行驱动开发,满足不同的硬件访问需求。

Linux字符设备设备驱动file_operationscdev修改时间:2026-07-04 12:33:35

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。