Linux 驱动开发:字符设备、块设备与网络设备驱动详解

文章目录

概要

[一. 字符设备驱动](#一. 字符设备驱动)

[1.1 概念](#1.1 概念)

[1.2 主要函数](#1.2 主要函数)

[1.3 开发流程](#1.3 开发流程)

[二. 块设备驱动](#二. 块设备驱动)

[2.1 概念](#2.1 概念)

[2.2 主要函数](#2.2 主要函数)

[2.3 开发流程](#2.3 开发流程)

[三. 网络设备驱动](#三. 网络设备驱动)

[3.1 概念](#3.1 概念)

[3.2 主要函数](#3.2 主要函数)

[3.3 开发流程](#3.3 开发流程)

概要

在 Linux 系统中,设备驱动是连接硬件与操作系统的桥梁。Linux 内核支持多种类型的设备驱动,主要包括字符设备驱动、块设备驱动和网络设备驱动。本文将详细介绍这三种设备驱动的概念、特点以及开发流程。

一. 字符设备驱动

1.1 概念

字符设备是指以字节流形式进行数据读写的设备,例如键盘、鼠标、串口等。字符设备驱动的主要特点是数据按顺序访问,不支持随机访问。

1.2 主要函数

  • open():打开设备。
  • release():关闭设备。
  • read():从设备读取数据。
  • write():向设备写入数据。
  • ioctl():设备控制操作。

1.3 开发流程

  1. 定义设备结构体,包含设备号、设备名称等信息。

  2. 实现 file_operations 结构体中的操作函数。

  3. 使用 register_chrdev() 注册字符设备。

  4. 创建设备文件节点,使用 mknod 命令。

  5. 测试驱动,通过用户空间程序访问设备。

如下即为字符设备驱动开发主要函数的定义:

复制代码
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "my_char_device"
static int major_number;

static int device_open(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Device opened\n");
    return 0;
}

static int device_release(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Device closed\n");
    return 0;
}

static ssize_t device_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) {
    printk(KERN_INFO "Device read\n");
    return 0;
}

static ssize_t device_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) {
    printk(KERN_INFO "Device write\n");
    return length;
}

static struct file_operations fops = {
    .open = device_open,
    .release = device_release,
    .read = device_read,
    .write = device_write,
};

static int __init my_char_device_init(void) {
    major_number = register_chrdev(0, DEVICE_NAME, &fops);
    if (major_number < 0) {
        printk(KERN_ALERT "Failed to register char device\n");
        return major_number;
    }
    printk(KERN_INFO "Char device registered with major number %d\n", major_number);
    return 0;
}

static void __exit my_char_device_exit(void) {
    unregister_chrdev(major_number, DEVICE_NAME);
    printk(KERN_INFO "Char device unregistered\n");
}

module_init(my_char_device_init);
module_exit(my_char_device_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("chelsea");
MODULE_DESCRIPTION("IMX6ULL");

二. 块设备驱动

2.1 概念

块设备是指以数据块为单位进行读写的设备,例如硬盘、SSD 等。块设备驱动支持随机访问,通常用于存储设备。

2.2 主要函数

  • open():打开设备。
  • release():关闭设备。
  • read():从设备读取数据块。
  • write():向设备写入数据块。
  • ioctl():设备控制操作。

2.3 开发流程

  1. 定义设备结构体,包含设备号、设备名称等信息。

  2. 实现 block_device_operations 结构体中的操作函数。

  3. 使用 register_blkdev() 注册块设备。

  4. 创建设备文件节点,使用 mknod 命令。

  5. 测试驱动,通过用户空间程序访问设备。

如下即为块设备驱动开发主要函数的定义:

复制代码
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/blkdev.h>

#define DEVICE_NAME "my_block_device"
static int major_number;
static struct gendisk *my_disk;

static int device_open(struct block_device *bdev, fmode_t mode) {
    printk(KERN_INFO "Block device opened\n");
    return 0;
}

static void device_release(struct gendisk *disk, fmode_t mode) {
    printk(KERN_INFO "Block device closed\n");
}

static struct block_device_operations fops = {
    .open = device_open,
    .release = device_release,
};

static int __init my_block_device_init(void) {
    major_number = register_blkdev(0, DEVICE_NAME);
    if (major_number < 0) {
        printk(KERN_ALERT "Failed to register block device\n");
        return major_number;
    }
    my_disk = alloc_disk(1);
    if (!my_disk) {
        unregister_blkdev(major_number, DEVICE_NAME);
        return -ENOMEM;
    }
    my_disk->major = major_number;
    my_disk->first_minor = 0;
    my_disk->fops = &fops;
    sprintf(my_disk->disk_name, "my_block_device");
    set_capacity(my_disk, 1024); // 1MB
    add_disk(my_disk);
    printk(KERN_INFO "Block device registered with major number %d\n", major_number);
    return 0;
}

static void __exit my_block_device_exit(void) {
    del_gendisk(my_disk);
    put_disk(my_disk);
    unregister_blkdev(major_number, DEVICE_NAME);
    printk(KERN_INFO "Block device unregistered\n");
}

module_init(my_block_device_init);
module_exit(my_block_device_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("chelsea");
MODULE_DESCRIPTION("IMX6ULL");

三. 网络设备驱动

3.1 概念

网络设备是指用于网络通信的设备,例如网卡、无线网卡等。网络设备驱动负责处理网络数据包的发送和接收。

3.2 主要函数

  • open():打开设备。
  • stop():关闭设备。
  • hard_start_xmit():发送数据包。
  • rx_handler():接收数据包。

3.3 开发流程

  1. 定义设备结构体,包含设备名称、MAC 地址等信息。

  2. 实现 net_device_ops 结构体中的操作函数。

  3. 使用 register_netdev() 注册网络设备。

  4. 配置网络设备,设置 IP 地址、子网掩码等。

  5. 测试驱动,通过用户空间程序访问设备。

如下即为网络设备驱动开发主要函数的定义:

复制代码
#include <linux/module.h>
#include <linux/netdevice.h>

#define DEVICE_NAME "my_net_device"
static struct net_device *my_net_device;

static int device_open(struct net_device *dev) {
    printk(KERN_INFO "Network device opened\n");
    netif_start_queue(dev);
    return 0;
}

static int device_stop(struct net_device *dev) {
    printk(KERN_INFO "Network device closed\n");
    netif_stop_queue(dev);
    return 0;
}

static netdev_tx_t device_start_xmit(struct sk_buff *skb, struct net_device *dev) {
    printk(KERN_INFO "Packet transmitted\n");
    dev_kfree_skb(skb);
    return NETDEV_TX_OK;
}

static struct net_device_ops netdev_ops = {
    .ndo_open = device_open,
    .ndo_stop = device_stop,
    .ndo_start_xmit = device_start_xmit,
};

static void device_setup(struct net_device *dev) {
    ether_setup(dev);
    dev->netdev_ops = &netdev_ops;
}

static int __init my_net_device_init(void) {
    my_net_device = alloc_netdev(0, DEVICE_NAME, NET_NAME_UNKNOWN, device_setup);
    if (!my_net_device) {
        return -ENOMEM;
    }
    if (register_netdev(my_net_device)) {
        free_netdev(my_net_device);
        return -1;
    }
    printk(KERN_INFO "Network device registered\n");
    return 0;
}

static void __exit my_net_device_exit(void) {
    unregister_netdev(my_net_device);
    free_netdev(my_net_device);
    printk(KERN_INFO "Network device unregistered\n");
}

module_init(my_net_device_init);
module_exit(my_net_device_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("chelsea);
MODULE_DESCRIPTION("IMX6ULL");
相关推荐
水墨长天10 分钟前
物联网协议 MQTT 快速开发与实践
后端·物联网
乱码三千24 分钟前
如何优雅地直连无公网 IP 的远程 GPU 服务器
linux·人工智能·程序员
yunwei3726 分钟前
使用 eBPF 跟踪 Nginx 请求
linux·后端·性能优化
yunwei3726 分钟前
使用 eBPF 跟踪 MySQL 查询
linux·后端·性能优化
yunwei3727 分钟前
eBPF 示例教程:使用 XDP 捕获 TCP 信息
linux·后端·性能优化
judezh28 分钟前
api 容器一直 unhealthy?我把一个 Agent 运行时的健康检查逐条拆了,查出四个问题
运维·docker
GeW31 分钟前
制造业高端化,为什么必须重估Linux和数据库?
linux
GeW38 分钟前
工业场景中的Linux与数据库选型:高端化转型的技术底座
linux
春天花会开13138 分钟前
内网 HTTPS 部署实战:私有 CA + Nginx 反向代理全流程复盘
运维·nginx·https
yunwei3739 分钟前
eBPF 开发者教程: 简单的 XDP 负载均衡器
linux·后端·性能优化