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");
相关推荐
Zevalin爱灰灰16 分钟前
编程技巧(基于STM32)第一章 定时器实现非阻塞式程序——按键控制LED灯闪烁模式
stm32·单片机·嵌入式硬件
鸡鸭扣36 分钟前
Docker:3、在VSCode上安装并运行python程序或JavaScript程序
运维·vscode·python·docker·容器·js
A ?Charis1 小时前
k8s-对接NFS存储
linux·服务器·kubernetes
饮长安千年月2 小时前
Linksys WRT54G路由器溢出漏洞分析–运行环境修复
网络·物联网·学习·安全·机器学习
红花与香菇2____2 小时前
【学习笔记】Cadence电子设计全流程(二)原理图库的创建与设计(上)
笔记·嵌入式硬件·学习·pcb设计·cadence·pcb工艺
mit6.8242 小时前
[实现Rpc] 通信类抽象层 | function | using | 解耦合设计思想
c++·网络协议·rpc
神秘_博士2 小时前
自制AirTag,支持安卓/鸿蒙/PC/Home Assistant,无需拥有iPhone
arm开发·python·物联网·flutter·docker·gitee
Jerry.yl2 小时前
关于 BK3633 上电时受串口 UART2 影响而无法启动的问题说明
嵌入式硬件·物联网·bk3633
苏慕TRYACE4 小时前
RT-Thread+STM32L475VET6实现红外遥控实验
stm32·单片机·嵌入式硬件·rt-thread
人工干智能4 小时前
科普:“Docker Desktop”和“Docker”以及“WSL”
运维·docker·容器